|
|
1.1 root 1: /* 1.1.1.6 ! root 2: Copyright (c) 2008-2010 TrueCrypt Developers Association. All rights reserved. 1.1 root 3: 1.1.1.6 ! root 4: Governed by the TrueCrypt License 3.0 the full text of which is contained in 1.1.1.5 root 5: the file License.txt included in TrueCrypt binary and source code distribution 6: packages. 1.1 root 7: */ 8: 9: #include "EncryptionThreadPool.h" 10: #include "Pkcs5.h" 11: #ifdef DEVICE_DRIVER 12: #include "Driver/Ntdriver.h" 13: #endif 14: 1.1.1.4 root 15: #define TC_ENC_THREAD_POOL_MAX_THREAD_COUNT 64 1.1 root 16: #define TC_ENC_THREAD_POOL_QUEUE_SIZE (TC_ENC_THREAD_POOL_MAX_THREAD_COUNT * 2) 17: 18: #ifdef DEVICE_DRIVER 19: 20: #define TC_THREAD_HANDLE PKTHREAD 21: #define TC_THREAD_PROC VOID 22: 23: #define TC_SET_EVENT(EVENT) KeSetEvent (&EVENT, IO_DISK_INCREMENT, FALSE) 24: #define TC_CLEAR_EVENT(EVENT) KeClearEvent (&EVENT) 25: 26: #define TC_MUTEX FAST_MUTEX 27: #define TC_ACQUIRE_MUTEX(MUTEX) ExAcquireFastMutex (MUTEX) 28: #define TC_RELEASE_MUTEX(MUTEX) ExReleaseFastMutex (MUTEX) 29: 30: #else // !DEVICE_DRIVER 31: 32: #define TC_THREAD_HANDLE HANDLE 33: #define TC_THREAD_PROC unsigned __stdcall 34: 35: #define TC_SET_EVENT(EVENT) SetEvent (EVENT) 36: #define TC_CLEAR_EVENT(EVENT) ResetEvent (EVENT) 37: 1.1.1.4 root 38: #define TC_MUTEX HANDLE 39: #define TC_ACQUIRE_MUTEX(MUTEX) WaitForSingleObject (*(MUTEX), INFINITE) 40: #define TC_RELEASE_MUTEX(MUTEX) ReleaseMutex (*(MUTEX)) 1.1 root 41: 42: #endif // !DEVICE_DRIVER 43: 44: 45: typedef enum 46: { 47: WorkItemFree, 48: WorkItemReady, 49: WorkItemBusy 50: } WorkItemState; 51: 52: 53: typedef struct EncryptionThreadPoolWorkItemStruct 54: { 55: WorkItemState State; 56: EncryptionThreadPoolWorkType Type; 57: 58: TC_EVENT ItemCompletedEvent; 59: 60: struct EncryptionThreadPoolWorkItemStruct *FirstFragment; 61: LONG OutstandingFragmentCount; 62: 63: union 64: { 65: struct 66: { 67: PCRYPTO_INFO CryptoInfo; 68: byte *Data; 69: UINT64_STRUCT StartUnitNo; 1.1.1.4 root 70: uint32 UnitCount; 1.1 root 71: 72: } Encryption; 73: 74: struct 75: { 76: TC_EVENT *CompletionEvent; 77: LONG *CompletionFlag; 78: char *DerivedKey; 79: int IterationCount; 80: TC_EVENT *NoOutstandingWorkItemEvent; 81: LONG *OutstandingWorkItemCount; 82: char *Password; 83: int PasswordLength; 84: int Pkcs5Prf; 85: char *Salt; 86: 87: } KeyDerivation; 88: }; 89: 90: } EncryptionThreadPoolWorkItem; 91: 92: 93: static volatile BOOL ThreadPoolRunning = FALSE; 94: static volatile BOOL StopPending = FALSE; 95: 1.1.1.4 root 96: static uint32 ThreadCount; 1.1 root 97: static TC_THREAD_HANDLE ThreadHandles[TC_ENC_THREAD_POOL_MAX_THREAD_COUNT]; 98: 99: static EncryptionThreadPoolWorkItem WorkItemQueue[TC_ENC_THREAD_POOL_QUEUE_SIZE]; 100: 101: static volatile int EnqueuePosition; 102: static volatile int DequeuePosition; 103: 104: static TC_MUTEX EnqueueMutex; 105: static TC_MUTEX DequeueMutex; 106: 107: static TC_EVENT WorkItemReadyEvent; 108: static TC_EVENT WorkItemCompletedEvent; 109: 110: 111: static WorkItemState GetWorkItemState (EncryptionThreadPoolWorkItem *workItem) 112: { 113: return InterlockedExchangeAdd ((LONG *) &workItem->State, 0); 114: } 115: 116: 117: static void SetWorkItemState (EncryptionThreadPoolWorkItem *workItem, WorkItemState newState) 118: { 119: InterlockedExchange ((LONG *) &workItem->State, (LONG) newState); 120: } 121: 122: 123: static TC_THREAD_PROC EncryptionThreadProc (void *threadArg) 124: { 125: EncryptionThreadPoolWorkItem *workItem; 126: 127: while (!StopPending) 128: { 129: TC_ACQUIRE_MUTEX (&DequeueMutex); 130: 131: workItem = &WorkItemQueue[DequeuePosition++]; 132: 133: if (DequeuePosition >= TC_ENC_THREAD_POOL_QUEUE_SIZE) 134: DequeuePosition = 0; 135: 136: while (!StopPending && GetWorkItemState (workItem) != WorkItemReady) 137: { 138: TC_WAIT_EVENT (WorkItemReadyEvent); 139: } 140: 141: SetWorkItemState (workItem, WorkItemBusy); 142: 143: TC_RELEASE_MUTEX (&DequeueMutex); 144: 145: if (StopPending) 146: break; 147: 148: switch (workItem->Type) 149: { 150: case DecryptDataUnitsWork: 151: DecryptDataUnitsCurrentThread (workItem->Encryption.Data, &workItem->Encryption.StartUnitNo, workItem->Encryption.UnitCount, workItem->Encryption.CryptoInfo); 152: break; 153: 154: case EncryptDataUnitsWork: 155: EncryptDataUnitsCurrentThread (workItem->Encryption.Data, &workItem->Encryption.StartUnitNo, workItem->Encryption.UnitCount, workItem->Encryption.CryptoInfo); 156: break; 157: 158: case DeriveKeyWork: 159: switch (workItem->KeyDerivation.Pkcs5Prf) 160: { 161: case RIPEMD160: 162: derive_key_ripemd160 (workItem->KeyDerivation.Password, workItem->KeyDerivation.PasswordLength, workItem->KeyDerivation.Salt, PKCS5_SALT_SIZE, 163: workItem->KeyDerivation.IterationCount, workItem->KeyDerivation.DerivedKey, GetMaxPkcs5OutSize()); 164: break; 165: 166: case SHA512: 167: derive_key_sha512 (workItem->KeyDerivation.Password, workItem->KeyDerivation.PasswordLength, workItem->KeyDerivation.Salt, PKCS5_SALT_SIZE, 168: workItem->KeyDerivation.IterationCount, workItem->KeyDerivation.DerivedKey, GetMaxPkcs5OutSize()); 169: break; 170: 171: case WHIRLPOOL: 172: derive_key_whirlpool (workItem->KeyDerivation.Password, workItem->KeyDerivation.PasswordLength, workItem->KeyDerivation.Salt, PKCS5_SALT_SIZE, 173: workItem->KeyDerivation.IterationCount, workItem->KeyDerivation.DerivedKey, GetMaxPkcs5OutSize()); 174: break; 175: 176: case SHA1: 177: derive_key_sha1 (workItem->KeyDerivation.Password, workItem->KeyDerivation.PasswordLength, workItem->KeyDerivation.Salt, PKCS5_SALT_SIZE, 178: workItem->KeyDerivation.IterationCount, workItem->KeyDerivation.DerivedKey, GetMaxPkcs5OutSize()); 179: break; 180: 181: default: 182: TC_THROW_FATAL_EXCEPTION; 183: } 184: 185: InterlockedExchange (workItem->KeyDerivation.CompletionFlag, TRUE); 186: TC_SET_EVENT (*workItem->KeyDerivation.CompletionEvent); 187: 188: if (InterlockedDecrement (workItem->KeyDerivation.OutstandingWorkItemCount) == 0) 189: TC_SET_EVENT (*workItem->KeyDerivation.NoOutstandingWorkItemEvent); 190: 191: SetWorkItemState (workItem, WorkItemFree); 192: TC_SET_EVENT (WorkItemCompletedEvent); 193: continue; 194: 195: default: 196: TC_THROW_FATAL_EXCEPTION; 197: } 198: 199: if (workItem != workItem->FirstFragment) 200: { 201: SetWorkItemState (workItem, WorkItemFree); 202: TC_SET_EVENT (WorkItemCompletedEvent); 203: } 204: 205: if (InterlockedDecrement (&workItem->FirstFragment->OutstandingFragmentCount) == 0) 206: TC_SET_EVENT (workItem->FirstFragment->ItemCompletedEvent); 207: } 208: 209: #ifdef DEVICE_DRIVER 210: PsTerminateSystemThread (STATUS_SUCCESS); 211: #else 212: _endthreadex (0); 213: return 0; 214: #endif 215: } 216: 217: 1.1.1.6 ! root 218: BOOL EncryptionThreadPoolStart (size_t encryptionFreeCpuCount) 1.1 root 219: { 220: size_t cpuCount, i; 221: 222: if (ThreadPoolRunning) 223: return TRUE; 224: 225: #ifdef DEVICE_DRIVER 226: cpuCount = GetCpuCount(); 227: #else 228: { 229: SYSTEM_INFO sysInfo; 230: GetSystemInfo (&sysInfo); 231: cpuCount = sysInfo.dwNumberOfProcessors; 232: } 233: #endif 234: 1.1.1.6 ! root 235: if (cpuCount > encryptionFreeCpuCount) ! 236: cpuCount -= encryptionFreeCpuCount; ! 237: 1.1 root 238: if (cpuCount < 2) 239: return TRUE; 240: 241: if (cpuCount > TC_ENC_THREAD_POOL_MAX_THREAD_COUNT) 242: cpuCount = TC_ENC_THREAD_POOL_MAX_THREAD_COUNT; 243: 244: StopPending = FALSE; 245: DequeuePosition = 0; 246: EnqueuePosition = 0; 247: 248: #ifdef DEVICE_DRIVER 249: KeInitializeEvent (&WorkItemReadyEvent, SynchronizationEvent, FALSE); 250: KeInitializeEvent (&WorkItemCompletedEvent, SynchronizationEvent, FALSE); 251: #else 252: WorkItemReadyEvent = CreateEvent (NULL, FALSE, FALSE, NULL); 253: if (!WorkItemReadyEvent) 254: return FALSE; 255: 256: WorkItemCompletedEvent = CreateEvent (NULL, FALSE, FALSE, NULL); 257: if (!WorkItemCompletedEvent) 258: return FALSE; 259: #endif 260: 1.1.1.4 root 261: #ifdef DEVICE_DRIVER 262: ExInitializeFastMutex (&DequeueMutex); 263: ExInitializeFastMutex (&EnqueueMutex); 264: #else 265: DequeueMutex = CreateMutex (NULL, FALSE, NULL); 266: if (!DequeueMutex) 267: return FALSE; 268: 269: EnqueueMutex = CreateMutex (NULL, FALSE, NULL); 270: if (!EnqueueMutex) 271: return FALSE; 272: #endif 1.1 root 273: 274: memset (WorkItemQueue, 0, sizeof (WorkItemQueue)); 275: 276: for (i = 0; i < sizeof (WorkItemQueue) / sizeof (WorkItemQueue[0]); ++i) 277: { 278: WorkItemQueue[i].State = WorkItemFree; 279: 280: #ifdef DEVICE_DRIVER 281: KeInitializeEvent (&WorkItemQueue[i].ItemCompletedEvent, SynchronizationEvent, FALSE); 282: #else 283: WorkItemQueue[i].ItemCompletedEvent = CreateEvent (NULL, FALSE, FALSE, NULL); 284: if (!WorkItemQueue[i].ItemCompletedEvent) 285: { 286: EncryptionThreadPoolStop(); 287: return FALSE; 288: } 289: #endif 290: } 291: 292: for (ThreadCount = 0; ThreadCount < cpuCount; ++ThreadCount) 293: { 294: #ifdef DEVICE_DRIVER 295: if (!NT_SUCCESS (TCStartThread (EncryptionThreadProc, NULL, &ThreadHandles[ThreadCount]))) 296: #else 297: if (!(ThreadHandles[ThreadCount] = (HANDLE) _beginthreadex (NULL, 0, EncryptionThreadProc, NULL, 0, NULL))) 298: #endif 299: { 300: EncryptionThreadPoolStop(); 301: return FALSE; 302: } 303: } 304: 305: ThreadPoolRunning = TRUE; 306: return TRUE; 307: } 308: 309: 310: void EncryptionThreadPoolStop () 311: { 312: size_t i; 313: 314: if (!ThreadPoolRunning) 315: return; 316: 317: StopPending = TRUE; 318: TC_SET_EVENT (WorkItemReadyEvent); 319: 320: for (i = 0; i < ThreadCount; ++i) 321: { 322: #ifdef DEVICE_DRIVER 323: TCStopThread (ThreadHandles[i], &WorkItemReadyEvent); 324: #else 325: TC_WAIT_EVENT (ThreadHandles[i]); 326: #endif 327: } 328: 329: ThreadCount = 0; 330: 331: #ifndef DEVICE_DRIVER 1.1.1.4 root 332: CloseHandle (DequeueMutex); 333: CloseHandle (EnqueueMutex); 1.1 root 334: 335: CloseHandle (WorkItemReadyEvent); 336: CloseHandle (WorkItemCompletedEvent); 337: 338: for (i = 0; i < sizeof (WorkItemQueue) / sizeof (WorkItemQueue[0]); ++i) 339: { 340: if (WorkItemQueue[i].ItemCompletedEvent) 341: CloseHandle (WorkItemQueue[i].ItemCompletedEvent); 342: } 343: #endif 344: 345: ThreadPoolRunning = FALSE; 346: } 347: 348: 349: void EncryptionThreadPoolBeginKeyDerivation (TC_EVENT *completionEvent, TC_EVENT *noOutstandingWorkItemEvent, LONG *completionFlag, LONG *outstandingWorkItemCount, int pkcs5Prf, char *password, int passwordLength, char *salt, int iterationCount, char *derivedKey) 350: { 351: EncryptionThreadPoolWorkItem *workItem; 352: 353: if (!ThreadPoolRunning) 354: TC_THROW_FATAL_EXCEPTION; 355: 356: TC_ACQUIRE_MUTEX (&EnqueueMutex); 357: 358: workItem = &WorkItemQueue[EnqueuePosition++]; 359: if (EnqueuePosition >= TC_ENC_THREAD_POOL_QUEUE_SIZE) 360: EnqueuePosition = 0; 361: 362: while (GetWorkItemState (workItem) != WorkItemFree) 363: { 364: TC_WAIT_EVENT (WorkItemCompletedEvent); 365: } 366: 367: workItem->Type = DeriveKeyWork; 368: workItem->KeyDerivation.CompletionEvent = completionEvent; 369: workItem->KeyDerivation.CompletionFlag = completionFlag; 370: workItem->KeyDerivation.DerivedKey = derivedKey; 371: workItem->KeyDerivation.IterationCount = iterationCount; 372: workItem->KeyDerivation.NoOutstandingWorkItemEvent = noOutstandingWorkItemEvent; 373: workItem->KeyDerivation.OutstandingWorkItemCount = outstandingWorkItemCount; 374: workItem->KeyDerivation.Password = password; 375: workItem->KeyDerivation.PasswordLength = passwordLength; 376: workItem->KeyDerivation.Pkcs5Prf = pkcs5Prf; 377: workItem->KeyDerivation.Salt = salt; 378: 379: InterlockedIncrement (outstandingWorkItemCount); 380: TC_CLEAR_EVENT (*noOutstandingWorkItemEvent); 381: 382: SetWorkItemState (workItem, WorkItemReady); 383: TC_SET_EVENT (WorkItemReadyEvent); 384: TC_RELEASE_MUTEX (&EnqueueMutex); 385: } 386: 387: 1.1.1.4 root 388: void EncryptionThreadPoolDoWork (EncryptionThreadPoolWorkType type, byte *data, const UINT64_STRUCT *startUnitNo, uint32 unitCount, PCRYPTO_INFO cryptoInfo) 1.1 root 389: { 1.1.1.4 root 390: uint32 fragmentCount; 391: uint32 unitsPerFragment; 392: uint32 remainder; 1.1 root 393: 394: byte *fragmentData; 1.1.1.4 root 395: uint64 fragmentStartUnitNo; 1.1 root 396: 397: EncryptionThreadPoolWorkItem *workItem; 398: EncryptionThreadPoolWorkItem *firstFragmentWorkItem; 399: 400: if (unitCount == 0) 401: return; 402: 403: if (!ThreadPoolRunning || unitCount == 1) 404: { 405: switch (type) 406: { 407: case DecryptDataUnitsWork: 408: DecryptDataUnitsCurrentThread (data, startUnitNo, unitCount, cryptoInfo); 409: break; 410: 411: case EncryptDataUnitsWork: 412: EncryptDataUnitsCurrentThread (data, startUnitNo, unitCount, cryptoInfo); 413: break; 414: 415: default: 416: TC_THROW_FATAL_EXCEPTION; 417: } 418: 419: return; 420: } 421: 422: if (unitCount <= ThreadCount) 423: { 1.1.1.4 root 424: fragmentCount = unitCount; 1.1 root 425: unitsPerFragment = 1; 426: remainder = 0; 427: } 428: else 429: { 430: /* Note that it is not efficient to divide the data into fragments smaller than a few hundred bytes. 431: The reason is that the overhead associated with thread handling would in most cases make a multi-threaded 432: process actually slower than a single-threaded process. */ 433: 434: fragmentCount = ThreadCount; 1.1.1.4 root 435: unitsPerFragment = unitCount / ThreadCount; 436: remainder = unitCount % ThreadCount; 1.1 root 437: 438: if (remainder > 0) 439: ++unitsPerFragment; 440: } 441: 442: fragmentData = data; 443: fragmentStartUnitNo = startUnitNo->Value; 444: 445: TC_ACQUIRE_MUTEX (&EnqueueMutex); 446: firstFragmentWorkItem = &WorkItemQueue[EnqueuePosition]; 447: 448: while (GetWorkItemState (firstFragmentWorkItem) != WorkItemFree) 449: { 450: TC_WAIT_EVENT (WorkItemCompletedEvent); 451: } 452: 453: firstFragmentWorkItem->OutstandingFragmentCount = fragmentCount; 454: 455: while (fragmentCount-- > 0) 456: { 457: workItem = &WorkItemQueue[EnqueuePosition++]; 458: if (EnqueuePosition >= TC_ENC_THREAD_POOL_QUEUE_SIZE) 459: EnqueuePosition = 0; 460: 461: while (GetWorkItemState (workItem) != WorkItemFree) 462: { 463: TC_WAIT_EVENT (WorkItemCompletedEvent); 464: } 465: 466: workItem->Type = type; 467: workItem->FirstFragment = firstFragmentWorkItem; 468: 469: workItem->Encryption.CryptoInfo = cryptoInfo; 470: workItem->Encryption.Data = fragmentData; 471: workItem->Encryption.UnitCount = unitsPerFragment; 472: workItem->Encryption.StartUnitNo.Value = fragmentStartUnitNo; 473: 474: fragmentData += unitsPerFragment * ENCRYPTION_DATA_UNIT_SIZE; 475: fragmentStartUnitNo += unitsPerFragment; 476: 477: if (remainder > 0 && --remainder == 0) 478: --unitsPerFragment; 479: 480: SetWorkItemState (workItem, WorkItemReady); 481: TC_SET_EVENT (WorkItemReadyEvent); 482: } 483: 484: TC_RELEASE_MUTEX (&EnqueueMutex); 485: 486: TC_WAIT_EVENT (firstFragmentWorkItem->ItemCompletedEvent); 487: SetWorkItemState (firstFragmentWorkItem, WorkItemFree); 488: TC_SET_EVENT (WorkItemCompletedEvent); 489: } 490: 491: 492: size_t GetEncryptionThreadCount () 493: { 494: return ThreadPoolRunning ? ThreadCount : 0; 495: } 496: 497: 1.1.1.6 ! root 498: size_t GetMaxEncryptionThreadCount () ! 499: { ! 500: return TC_ENC_THREAD_POOL_MAX_THREAD_COUNT; ! 501: } ! 502: ! 503: 1.1 root 504: BOOL IsEncryptionThreadPoolRunning () 505: { 506: return ThreadPoolRunning; 507: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.