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