|
|
1.1 root 1: /* 1.1.1.4 ! root 2: Copyright (c) 2008-2009 TrueCrypt Foundation. All rights reserved. 1.1 root 3: 1.1.1.4 ! root 4: Governed by the TrueCrypt License 2.8 the full text of which is contained 1.1 root 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: 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: 218: BOOL EncryptionThreadPoolStart () 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: 235: if (cpuCount < 2) 236: return TRUE; 237: 238: if (cpuCount > TC_ENC_THREAD_POOL_MAX_THREAD_COUNT) 239: cpuCount = TC_ENC_THREAD_POOL_MAX_THREAD_COUNT; 240: 241: StopPending = FALSE; 242: DequeuePosition = 0; 243: EnqueuePosition = 0; 244: 245: #ifdef DEVICE_DRIVER 246: KeInitializeEvent (&WorkItemReadyEvent, SynchronizationEvent, FALSE); 247: KeInitializeEvent (&WorkItemCompletedEvent, SynchronizationEvent, FALSE); 248: #else 249: WorkItemReadyEvent = CreateEvent (NULL, FALSE, FALSE, NULL); 250: if (!WorkItemReadyEvent) 251: return FALSE; 252: 253: WorkItemCompletedEvent = CreateEvent (NULL, FALSE, FALSE, NULL); 254: if (!WorkItemCompletedEvent) 255: return FALSE; 256: #endif 257: 1.1.1.4 ! root 258: #ifdef DEVICE_DRIVER ! 259: ExInitializeFastMutex (&DequeueMutex); ! 260: ExInitializeFastMutex (&EnqueueMutex); ! 261: #else ! 262: DequeueMutex = CreateMutex (NULL, FALSE, NULL); ! 263: if (!DequeueMutex) ! 264: return FALSE; ! 265: ! 266: EnqueueMutex = CreateMutex (NULL, FALSE, NULL); ! 267: if (!EnqueueMutex) ! 268: return FALSE; ! 269: #endif 1.1 root 270: 271: memset (WorkItemQueue, 0, sizeof (WorkItemQueue)); 272: 273: for (i = 0; i < sizeof (WorkItemQueue) / sizeof (WorkItemQueue[0]); ++i) 274: { 275: WorkItemQueue[i].State = WorkItemFree; 276: 277: #ifdef DEVICE_DRIVER 278: KeInitializeEvent (&WorkItemQueue[i].ItemCompletedEvent, SynchronizationEvent, FALSE); 279: #else 280: WorkItemQueue[i].ItemCompletedEvent = CreateEvent (NULL, FALSE, FALSE, NULL); 281: if (!WorkItemQueue[i].ItemCompletedEvent) 282: { 283: EncryptionThreadPoolStop(); 284: return FALSE; 285: } 286: #endif 287: } 288: 289: for (ThreadCount = 0; ThreadCount < cpuCount; ++ThreadCount) 290: { 291: #ifdef DEVICE_DRIVER 292: if (!NT_SUCCESS (TCStartThread (EncryptionThreadProc, NULL, &ThreadHandles[ThreadCount]))) 293: #else 294: if (!(ThreadHandles[ThreadCount] = (HANDLE) _beginthreadex (NULL, 0, EncryptionThreadProc, NULL, 0, NULL))) 295: #endif 296: { 297: EncryptionThreadPoolStop(); 298: return FALSE; 299: } 300: } 301: 302: ThreadPoolRunning = TRUE; 303: return TRUE; 304: } 305: 306: 307: void EncryptionThreadPoolStop () 308: { 309: size_t i; 310: 311: if (!ThreadPoolRunning) 312: return; 313: 314: StopPending = TRUE; 315: TC_SET_EVENT (WorkItemReadyEvent); 316: 317: for (i = 0; i < ThreadCount; ++i) 318: { 319: #ifdef DEVICE_DRIVER 320: TCStopThread (ThreadHandles[i], &WorkItemReadyEvent); 321: #else 322: TC_WAIT_EVENT (ThreadHandles[i]); 323: #endif 324: } 325: 326: ThreadCount = 0; 327: 328: #ifndef DEVICE_DRIVER 1.1.1.4 ! root 329: CloseHandle (DequeueMutex); ! 330: CloseHandle (EnqueueMutex); 1.1 root 331: 332: CloseHandle (WorkItemReadyEvent); 333: CloseHandle (WorkItemCompletedEvent); 334: 335: for (i = 0; i < sizeof (WorkItemQueue) / sizeof (WorkItemQueue[0]); ++i) 336: { 337: if (WorkItemQueue[i].ItemCompletedEvent) 338: CloseHandle (WorkItemQueue[i].ItemCompletedEvent); 339: } 340: #endif 341: 342: ThreadPoolRunning = FALSE; 343: } 344: 345: 346: void EncryptionThreadPoolBeginKeyDerivation (TC_EVENT *completionEvent, TC_EVENT *noOutstandingWorkItemEvent, LONG *completionFlag, LONG *outstandingWorkItemCount, int pkcs5Prf, char *password, int passwordLength, char *salt, int iterationCount, char *derivedKey) 347: { 348: EncryptionThreadPoolWorkItem *workItem; 349: 350: if (!ThreadPoolRunning) 351: TC_THROW_FATAL_EXCEPTION; 352: 353: TC_ACQUIRE_MUTEX (&EnqueueMutex); 354: 355: workItem = &WorkItemQueue[EnqueuePosition++]; 356: if (EnqueuePosition >= TC_ENC_THREAD_POOL_QUEUE_SIZE) 357: EnqueuePosition = 0; 358: 359: while (GetWorkItemState (workItem) != WorkItemFree) 360: { 361: TC_WAIT_EVENT (WorkItemCompletedEvent); 362: } 363: 364: workItem->Type = DeriveKeyWork; 365: workItem->KeyDerivation.CompletionEvent = completionEvent; 366: workItem->KeyDerivation.CompletionFlag = completionFlag; 367: workItem->KeyDerivation.DerivedKey = derivedKey; 368: workItem->KeyDerivation.IterationCount = iterationCount; 369: workItem->KeyDerivation.NoOutstandingWorkItemEvent = noOutstandingWorkItemEvent; 370: workItem->KeyDerivation.OutstandingWorkItemCount = outstandingWorkItemCount; 371: workItem->KeyDerivation.Password = password; 372: workItem->KeyDerivation.PasswordLength = passwordLength; 373: workItem->KeyDerivation.Pkcs5Prf = pkcs5Prf; 374: workItem->KeyDerivation.Salt = salt; 375: 376: InterlockedIncrement (outstandingWorkItemCount); 377: TC_CLEAR_EVENT (*noOutstandingWorkItemEvent); 378: 379: SetWorkItemState (workItem, WorkItemReady); 380: TC_SET_EVENT (WorkItemReadyEvent); 381: TC_RELEASE_MUTEX (&EnqueueMutex); 382: } 383: 384: 1.1.1.4 ! root 385: void EncryptionThreadPoolDoWork (EncryptionThreadPoolWorkType type, byte *data, const UINT64_STRUCT *startUnitNo, uint32 unitCount, PCRYPTO_INFO cryptoInfo) 1.1 root 386: { 1.1.1.4 ! root 387: uint32 fragmentCount; ! 388: uint32 unitsPerFragment; ! 389: uint32 remainder; 1.1 root 390: 391: byte *fragmentData; 1.1.1.4 ! root 392: uint64 fragmentStartUnitNo; 1.1 root 393: 394: EncryptionThreadPoolWorkItem *workItem; 395: EncryptionThreadPoolWorkItem *firstFragmentWorkItem; 396: 397: if (unitCount == 0) 398: return; 399: 400: if (!ThreadPoolRunning || unitCount == 1) 401: { 402: switch (type) 403: { 404: case DecryptDataUnitsWork: 405: DecryptDataUnitsCurrentThread (data, startUnitNo, unitCount, cryptoInfo); 406: break; 407: 408: case EncryptDataUnitsWork: 409: EncryptDataUnitsCurrentThread (data, startUnitNo, unitCount, cryptoInfo); 410: break; 411: 412: default: 413: TC_THROW_FATAL_EXCEPTION; 414: } 415: 416: return; 417: } 418: 419: if (unitCount <= ThreadCount) 420: { 1.1.1.4 ! root 421: fragmentCount = unitCount; 1.1 root 422: unitsPerFragment = 1; 423: remainder = 0; 424: } 425: else 426: { 427: /* Note that it is not efficient to divide the data into fragments smaller than a few hundred bytes. 428: The reason is that the overhead associated with thread handling would in most cases make a multi-threaded 429: process actually slower than a single-threaded process. */ 430: 431: fragmentCount = ThreadCount; 1.1.1.4 ! root 432: unitsPerFragment = unitCount / ThreadCount; ! 433: remainder = unitCount % ThreadCount; 1.1 root 434: 435: if (remainder > 0) 436: ++unitsPerFragment; 437: } 438: 439: fragmentData = data; 440: fragmentStartUnitNo = startUnitNo->Value; 441: 442: TC_ACQUIRE_MUTEX (&EnqueueMutex); 443: firstFragmentWorkItem = &WorkItemQueue[EnqueuePosition]; 444: 445: while (GetWorkItemState (firstFragmentWorkItem) != WorkItemFree) 446: { 447: TC_WAIT_EVENT (WorkItemCompletedEvent); 448: } 449: 450: firstFragmentWorkItem->OutstandingFragmentCount = fragmentCount; 451: 452: while (fragmentCount-- > 0) 453: { 454: workItem = &WorkItemQueue[EnqueuePosition++]; 455: if (EnqueuePosition >= TC_ENC_THREAD_POOL_QUEUE_SIZE) 456: EnqueuePosition = 0; 457: 458: while (GetWorkItemState (workItem) != WorkItemFree) 459: { 460: TC_WAIT_EVENT (WorkItemCompletedEvent); 461: } 462: 463: workItem->Type = type; 464: workItem->FirstFragment = firstFragmentWorkItem; 465: 466: workItem->Encryption.CryptoInfo = cryptoInfo; 467: workItem->Encryption.Data = fragmentData; 468: workItem->Encryption.UnitCount = unitsPerFragment; 469: workItem->Encryption.StartUnitNo.Value = fragmentStartUnitNo; 470: 471: fragmentData += unitsPerFragment * ENCRYPTION_DATA_UNIT_SIZE; 472: fragmentStartUnitNo += unitsPerFragment; 473: 474: if (remainder > 0 && --remainder == 0) 475: --unitsPerFragment; 476: 477: SetWorkItemState (workItem, WorkItemReady); 478: TC_SET_EVENT (WorkItemReadyEvent); 479: } 480: 481: TC_RELEASE_MUTEX (&EnqueueMutex); 482: 483: TC_WAIT_EVENT (firstFragmentWorkItem->ItemCompletedEvent); 484: SetWorkItemState (firstFragmentWorkItem, WorkItemFree); 485: TC_SET_EVENT (WorkItemCompletedEvent); 486: } 487: 488: 489: size_t GetEncryptionThreadCount () 490: { 491: return ThreadPoolRunning ? ThreadCount : 0; 492: } 493: 494: 495: BOOL IsEncryptionThreadPoolRunning () 496: { 497: return ThreadPoolRunning; 498: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.