|
|
1.1 root 1: /*
2: Copyright (c) 2008 TrueCrypt Foundation. All rights reserved.
3:
1.1.1.3 ! root 4: Governed by the TrueCrypt License 2.7 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:
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.