"Fossies" - the Fresh Open Source Software Archive

Member "src/Common/EncryptionThreadPool.c" (10 Oct 2018, 13586 Bytes) of package /windows/misc/VeraCrypt_1.23-Hotfix-2_Source.zip:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "EncryptionThreadPool.c" see the Fossies "Dox" file reference documentation.

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