"Fossies" - the Fresh Open Source Software Archive

Member "src/Common/Random.c" (10 Oct 2018, 25318 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 "Random.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 1.18_Source_vs_1.19_Source.

    1 /*
    2  Legal Notice: Some portions of the source code contained in this file were
    3  derived from the source code of TrueCrypt 7.1a, which is
    4  Copyright (c) 2003-2012 TrueCrypt Developers Association and which is
    5  governed by the TrueCrypt License 3.0, also from the source code of
    6  Encryption for the Masses 2.02a, which is Copyright (c) 1998-2000 Paul Le Roux
    7  and which is governed by the 'License Agreement for Encryption for the Masses'
    8  Modifications and additions to the original source code (contained in this file)
    9  and all other portions of this file are Copyright (c) 2013-2017 IDRIX
   10  and are governed by the Apache License 2.0 the full text of which is
   11  contained in the file License.txt included in VeraCrypt binary and source
   12  code distribution packages. */
   13 
   14 #include "Tcdefs.h"
   15 #include "Crc.h"
   16 #include "Random.h"
   17 #include <Strsafe.h>
   18 
   19 static unsigned __int8 buffer[RNG_POOL_SIZE];
   20 static unsigned char *pRandPool = NULL;
   21 static BOOL bRandDidInit = FALSE;
   22 static int nRandIndex = 0, randPoolReadIndex = 0;
   23 static int HashFunction = DEFAULT_HASH_ALGORITHM;
   24 static BOOL bDidSlowPoll = FALSE;
   25 BOOL volatile bFastPollEnabled = TRUE;  /* Used to reduce CPU load when performing benchmarks */
   26 BOOL volatile bRandmixEnabled = TRUE;   /* Used to reduce CPU load when performing benchmarks */
   27 static BOOL RandomPoolEnrichedByUser = FALSE;
   28 static HANDLE PeriodicFastPollThreadHandle = NULL;
   29 
   30 /* Macro to add a single byte to the pool */
   31 #define RandaddByte(x) {\
   32     if (nRandIndex == RNG_POOL_SIZE) nRandIndex = 0;\
   33     pRandPool[nRandIndex] = (unsigned char) ((unsigned char)x + pRandPool[nRandIndex]); \
   34     if (nRandIndex % RANDMIX_BYTE_INTERVAL == 0) Randmix();\
   35     nRandIndex++; \
   36     }
   37 
   38 /* Macro to add four bytes to the pool */
   39 #define RandaddInt32(x) RandAddInt((unsigned __int32)x);
   40 
   41 #ifdef _WIN64
   42 #define RandaddIntPtr(x) RandAddInt64((unsigned __int64)x);
   43 #else
   44 #define RandaddIntPtr(x) RandAddInt((unsigned __int32)x);
   45 #endif
   46 
   47 void RandAddInt (unsigned __int32 x)
   48 {
   49     RandaddByte(x);
   50     RandaddByte((x >> 8));
   51     RandaddByte((x >> 16));
   52     RandaddByte((x >> 24));
   53 }
   54 
   55 void RandAddInt64 (unsigned __int64 x)
   56 {
   57     RandaddByte(x);
   58     RandaddByte((x >> 8));
   59     RandaddByte((x >> 16));
   60     RandaddByte((x >> 24));
   61 
   62     RandaddByte((x >> 32));
   63     RandaddByte((x >> 40));
   64     RandaddByte((x >> 48));
   65     RandaddByte((x >> 56));
   66 }
   67 
   68 #include <tlhelp32.h>
   69 #include "Dlgcode.h"
   70 
   71 #ifndef SRC_POS
   72 #define SRC_POS (__FUNCTION__ ":" TC_TO_STRING(__LINE__))
   73 #endif
   74 
   75 HHOOK hMouse = NULL;        /* Mouse hook for the random number generator */
   76 HHOOK hKeyboard = NULL;     /* Keyboard hook for the random number generator */
   77 DWORD ProcessedMouseEventsCounter = 0;
   78 
   79 /* Variables for thread control, the thread is used to gather up info about
   80    the system in in the background */
   81 CRITICAL_SECTION critRandProt;  /* The critical section */
   82 BOOL volatile bThreadTerminate = FALSE; /* This variable is shared among thread's so its made volatile */
   83 
   84 /* Network library handle for the SlowPoll function */
   85 HANDLE hNetAPI32 = NULL;
   86 
   87 // CryptoAPI
   88 BOOL CryptoAPIAvailable = FALSE;
   89 DWORD CryptoAPILastError = ERROR_SUCCESS;
   90 HCRYPTPROV hCryptProv;
   91 
   92 
   93 /* Init the random number generator, setup the hooks, and start the thread */
   94 int Randinit ()
   95 {
   96     DWORD dwLastError = ERROR_SUCCESS;
   97     if (GetMaxPkcs5OutSize() > RNG_POOL_SIZE)
   98         TC_THROW_FATAL_EXCEPTION;
   99 
  100     if(bRandDidInit)
  101         return 0;
  102 
  103     InitializeCriticalSection (&critRandProt);
  104 
  105     bRandDidInit = TRUE;
  106     CryptoAPILastError = ERROR_SUCCESS;
  107     ProcessedMouseEventsCounter = 0;
  108 
  109     if (pRandPool == NULL)
  110     {
  111         pRandPool = (unsigned char *) _aligned_malloc (RANDOMPOOL_ALLOCSIZE, 16);
  112         if (pRandPool == NULL)
  113             goto error;
  114 
  115         bDidSlowPoll = FALSE;
  116         RandomPoolEnrichedByUser = FALSE;
  117 
  118         memset (pRandPool, 0, RANDOMPOOL_ALLOCSIZE);
  119         VirtualLock (pRandPool, RANDOMPOOL_ALLOCSIZE);
  120     }
  121 
  122     hKeyboard = SetWindowsHookEx (WH_KEYBOARD, (HOOKPROC)&KeyboardProc, NULL, GetCurrentThreadId ());
  123     if (hKeyboard == 0) handleWin32Error (0, SRC_POS);
  124 
  125     hMouse = SetWindowsHookEx (WH_MOUSE, (HOOKPROC)&MouseProc, NULL, GetCurrentThreadId ());
  126     if (hMouse == 0)
  127     {
  128         handleWin32Error (0, SRC_POS);
  129         goto error;
  130     }
  131 
  132     if (!CryptAcquireContext (&hCryptProv, NULL, MS_ENHANCED_PROV, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT | CRYPT_SILENT))
  133     {
  134         CryptoAPIAvailable = FALSE;
  135         CryptoAPILastError = GetLastError ();
  136         goto error;
  137     }
  138     else
  139         CryptoAPIAvailable = TRUE;
  140 
  141     if (!(PeriodicFastPollThreadHandle = (HANDLE) _beginthreadex (NULL, 0, PeriodicFastPollThreadProc, NULL, 0, NULL)))
  142         goto error;
  143 
  144     return 0;
  145 
  146 error:
  147     dwLastError = GetLastError();
  148     RandStop (TRUE);
  149     SetLastError (dwLastError);
  150     return 1;
  151 }
  152 
  153 /* Close everything down, including the thread which is closed down by
  154    setting a flag which eventually causes the thread function to exit */
  155 void RandStop (BOOL freePool)
  156 {
  157     if (!bRandDidInit && freePool && pRandPool)
  158         goto freePool;
  159 
  160     if (bRandDidInit == FALSE)
  161         return;
  162 
  163     EnterCriticalSection (&critRandProt);
  164 
  165     if (hMouse != 0)
  166         UnhookWindowsHookEx (hMouse);
  167     if (hKeyboard != 0)
  168         UnhookWindowsHookEx (hKeyboard);
  169 
  170     bThreadTerminate = TRUE;
  171 
  172     LeaveCriticalSection (&critRandProt);
  173 
  174     if (PeriodicFastPollThreadHandle)
  175         WaitForSingleObject (PeriodicFastPollThreadHandle, INFINITE);
  176 
  177     if (hNetAPI32 != 0)
  178     {
  179         FreeLibrary (hNetAPI32);
  180         hNetAPI32 = NULL;
  181     }
  182 
  183     if (CryptoAPIAvailable)
  184     {
  185         CryptReleaseContext (hCryptProv, 0);
  186         CryptoAPIAvailable = FALSE;
  187         CryptoAPILastError = ERROR_SUCCESS;
  188     }
  189 
  190     hMouse = NULL;
  191     hKeyboard = NULL;
  192     bThreadTerminate = FALSE;
  193     DeleteCriticalSection (&critRandProt);
  194 
  195     bRandDidInit = FALSE;
  196 
  197 freePool:
  198     if (freePool)
  199     {
  200         bDidSlowPoll = FALSE;
  201         RandomPoolEnrichedByUser = FALSE;
  202 
  203         if (pRandPool != NULL)
  204         {
  205             burn (pRandPool, RANDOMPOOL_ALLOCSIZE);
  206             _aligned_free (pRandPool);
  207             pRandPool = NULL;
  208         }
  209     }
  210 }
  211 
  212 BOOL IsRandomNumberGeneratorStarted ()
  213 {
  214     return bRandDidInit;
  215 }
  216 
  217 void RandSetHashFunction (int hash_algo_id)
  218 {
  219     if (HashIsDeprecated (hash_algo_id))
  220         hash_algo_id = DEFAULT_HASH_ALGORITHM;
  221 
  222     HashFunction = hash_algo_id;
  223 }
  224 
  225 int RandGetHashFunction (void)
  226 {
  227     return HashFunction;
  228 }
  229 
  230 void SetRandomPoolEnrichedByUserStatus (BOOL enriched)
  231 {
  232     RandomPoolEnrichedByUser = enriched;
  233 }
  234 
  235 BOOL IsRandomPoolEnrichedByUser ()
  236 {
  237     return RandomPoolEnrichedByUser;
  238 }
  239 
  240 /* The random pool mixing function */
  241 BOOL Randmix ()
  242 {
  243     if (bRandmixEnabled)
  244     {
  245         unsigned char hashOutputBuffer [MAX_DIGESTSIZE];
  246         WHIRLPOOL_CTX   wctx;
  247         RMD160_CTX      rctx;
  248         sha512_ctx      sctx;
  249         sha256_ctx      s256ctx;
  250         STREEBOG_CTX    stctx;
  251         int poolIndex, digestIndex, digestSize;
  252 
  253         switch (HashFunction)
  254         {
  255         case RIPEMD160:
  256             digestSize = RIPEMD160_DIGESTSIZE;
  257             break;
  258 
  259         case SHA512:
  260             digestSize = SHA512_DIGESTSIZE;
  261             break;
  262 
  263         case SHA256:
  264             digestSize = SHA256_DIGESTSIZE;
  265             break;
  266 
  267         case WHIRLPOOL:
  268             digestSize = WHIRLPOOL_DIGESTSIZE;
  269             break;
  270 
  271         case STREEBOG:
  272             digestSize = STREEBOG_DIGESTSIZE;
  273             break;
  274 
  275         default:
  276             TC_THROW_FATAL_EXCEPTION;
  277         }
  278 
  279         if (RNG_POOL_SIZE % digestSize)
  280             TC_THROW_FATAL_EXCEPTION;
  281 
  282         for (poolIndex = 0; poolIndex < RNG_POOL_SIZE; poolIndex += digestSize)
  283         {
  284             /* Compute the message digest of the entire pool using the selected hash function. */
  285             switch (HashFunction)
  286             {
  287             case RIPEMD160:
  288                 RMD160Init(&rctx);
  289                 RMD160Update(&rctx, pRandPool, RNG_POOL_SIZE);
  290                 RMD160Final(hashOutputBuffer, &rctx);
  291                 break;
  292 
  293             case SHA512:
  294                 sha512_begin (&sctx);
  295                 sha512_hash (pRandPool, RNG_POOL_SIZE, &sctx);
  296                 sha512_end (hashOutputBuffer, &sctx);
  297                 break;
  298 
  299             case SHA256:
  300                 sha256_begin (&s256ctx);
  301                 sha256_hash (pRandPool, RNG_POOL_SIZE, &s256ctx);
  302                 sha256_end (hashOutputBuffer, &s256ctx);
  303                 break;
  304 
  305             case WHIRLPOOL:
  306                 WHIRLPOOL_init (&wctx);
  307                 WHIRLPOOL_add (pRandPool, RNG_POOL_SIZE, &wctx);
  308                 WHIRLPOOL_finalize (&wctx, hashOutputBuffer);
  309                 break;
  310 
  311             case STREEBOG:
  312                 STREEBOG_init (&stctx);
  313                 STREEBOG_add (&stctx, pRandPool, RNG_POOL_SIZE);
  314                 STREEBOG_finalize (&stctx, hashOutputBuffer);
  315                 break;
  316 
  317             default:
  318                 // Unknown/wrong ID
  319                 TC_THROW_FATAL_EXCEPTION;
  320             }
  321 
  322             /* XOR the resultant message digest to the pool at the poolIndex position. */
  323             for (digestIndex = 0; digestIndex < digestSize; digestIndex++)
  324             {
  325                 pRandPool [poolIndex + digestIndex] ^= hashOutputBuffer [digestIndex];
  326             }
  327         }
  328 
  329         /* Prevent leaks */
  330         burn (hashOutputBuffer, MAX_DIGESTSIZE);
  331         switch (HashFunction)
  332         {
  333         case RIPEMD160:
  334             burn (&rctx, sizeof(rctx));
  335             break;
  336 
  337         case SHA512:
  338             burn (&sctx, sizeof(sctx));
  339             break;
  340 
  341         case SHA256:
  342             burn (&s256ctx, sizeof(s256ctx));
  343             break;
  344 
  345         case WHIRLPOOL:
  346             burn (&wctx, sizeof(wctx));
  347             break;
  348 
  349         case STREEBOG:
  350             burn (&stctx, sizeof(sctx));
  351             break;
  352 
  353         default:
  354             // Unknown/wrong ID
  355             TC_THROW_FATAL_EXCEPTION;
  356         }
  357     }
  358     return TRUE;
  359 }
  360 
  361 /* Add a buffer to the pool */
  362 void RandaddBuf (void *buf, int len)
  363 {
  364     int i;
  365     for (i = 0; i < len; i++)
  366     {
  367         RandaddByte (((unsigned char *) buf)[i]);
  368     }
  369 }
  370 
  371 BOOL RandpeekBytes (void* hwndDlg, unsigned char *buf, int len, DWORD* mouseCounter)
  372 {
  373     if (!bRandDidInit)
  374         return FALSE;
  375 
  376     if (len > RNG_POOL_SIZE)
  377     {
  378         Error ("ERR_NOT_ENOUGH_RANDOM_DATA", (HWND) hwndDlg);
  379         len = RNG_POOL_SIZE;
  380     }
  381 
  382     EnterCriticalSection (&critRandProt);
  383     *mouseCounter = ProcessedMouseEventsCounter;
  384     memcpy (buf, pRandPool, len);
  385     LeaveCriticalSection (&critRandProt);
  386 
  387     return TRUE;
  388 }
  389 
  390 
  391 /* Get len random bytes from the pool (max. RNG_POOL_SIZE bytes per a single call) */
  392 BOOL RandgetBytes (void* hwndDlg, unsigned char *buf, int len, BOOL forceSlowPoll)
  393 {
  394     return RandgetBytesFull (hwndDlg, buf, len, forceSlowPoll, FALSE);
  395 }
  396 
  397 /* Get len random bytes from the pool.
  398  *  If allowAnyLength is FALSE, then len must be less or equal to RNG_POOL_SIZE
  399  *  If allowAnyLength is TRUE, then len can have any positive value
  400  */
  401 BOOL RandgetBytesFull ( void* hwndDlg, unsigned char *buf , int len, BOOL forceSlowPoll , BOOL allowAnyLength)
  402 {
  403     int i, looplen;
  404     BOOL ret = TRUE;
  405 
  406     if (!bRandDidInit || HashFunction == 0)
  407         TC_THROW_FATAL_EXCEPTION;
  408 
  409     EnterCriticalSection (&critRandProt);
  410 
  411     if (bDidSlowPoll == FALSE || forceSlowPoll)
  412     {
  413         if (!SlowPoll ())
  414         {
  415             handleError ((HWND) hwndDlg, ERR_CAPI_INIT_FAILED, SRC_POS);
  416             ret = FALSE;
  417         }
  418         else
  419             bDidSlowPoll = TRUE;
  420     }
  421 
  422     if (!FastPoll ())
  423     {
  424         handleError ((HWND) hwndDlg, ERR_CAPI_INIT_FAILED, SRC_POS);
  425         ret = FALSE;
  426     }
  427 
  428     /* There's never more than RNG_POOL_SIZE worth of randomess */
  429     if ( (!allowAnyLength) && (len > RNG_POOL_SIZE))
  430     {
  431         Error ("ERR_NOT_ENOUGH_RANDOM_DATA", (HWND) hwndDlg);
  432         len = RNG_POOL_SIZE;
  433         LeaveCriticalSection (&critRandProt);
  434         return FALSE;
  435     }
  436 
  437     while (len > 0)
  438     {
  439         if (len > RNG_POOL_SIZE)
  440         {
  441             looplen = RNG_POOL_SIZE;
  442             len -= RNG_POOL_SIZE;
  443         }
  444         else
  445         {
  446             looplen = len;
  447             len = 0;
  448         }
  449 
  450         // this loop number of bytes is copied from pool to output buffer,
  451         // pool is rehashed, and output buffer is XORed with new data from pool
  452         for (i = 0; i < looplen; i++)
  453         {
  454             buf[i] = pRandPool[randPoolReadIndex++];
  455             if (randPoolReadIndex == RNG_POOL_SIZE) randPoolReadIndex = 0;
  456         }
  457 
  458         /* Invert the pool */
  459         for (i = 0; i < RNG_POOL_SIZE / 4; i++)
  460         {
  461             ((unsigned __int32 *) pRandPool)[i] = ~((unsigned __int32 *) pRandPool)[i];
  462         }
  463 
  464         // Mix the pool
  465         if (!FastPoll ())
  466             ret = FALSE;
  467 
  468         // XOR the current pool content into the output buffer to prevent pool state leaks
  469         for (i = 0; i < looplen; i++)
  470         {
  471             buf[i] ^= pRandPool[randPoolReadIndex++];
  472             if (randPoolReadIndex == RNG_POOL_SIZE) randPoolReadIndex = 0;
  473         }
  474 
  475         // increment the pointer for the next loop
  476         buf += looplen;
  477     }
  478 
  479     LeaveCriticalSection (&critRandProt);
  480 
  481     if (!ret)
  482         TC_THROW_FATAL_EXCEPTION;
  483 
  484     return ret;
  485 }
  486 
  487 /* Capture the mouse, and as long as the event is not the same as the last
  488    two events, add the crc of the event, and the crc of the time difference
  489    between this event and the last + the current time to the pool.
  490    The role of CRC-32 is merely to perform diffusion. Note that the output
  491    of CRC-32 is subsequently processed using a cryptographically secure hash
  492    algorithm. */
  493 LRESULT CALLBACK MouseProc (int nCode, WPARAM wParam, LPARAM lParam)
  494 {
  495     static DWORD dwLastTimer;
  496     static unsigned __int32 lastCrc, lastCrc2;
  497     static POINT lastPoint;
  498     MOUSEHOOKSTRUCT *lpMouse = (MOUSEHOOKSTRUCT *) lParam;
  499 
  500     if (nCode < 0)
  501         return CallNextHookEx (hMouse, nCode, wParam, lParam);
  502     else
  503     {
  504         DWORD dwTimer = GetTickCount ();
  505         DWORD j = dwLastTimer - dwTimer;
  506         unsigned __int32 crc = 0L;
  507         int i;
  508         POINT pt = lpMouse->pt;
  509 
  510         dwLastTimer = dwTimer;
  511 
  512         for (i = 0; i < sizeof (MOUSEHOOKSTRUCT); i++)
  513         {
  514             crc = UPDC32 (((unsigned char *) lpMouse)[i], crc);
  515         }
  516 
  517         if (crc != lastCrc && crc != lastCrc2)
  518         {
  519             unsigned __int32 timeCrc = 0L;
  520 
  521             for (i = 0; i < 4; i++)
  522             {
  523                 timeCrc = UPDC32 (((unsigned char *) &j)[i], timeCrc);
  524             }
  525 
  526             for (i = 0; i < 4; i++)
  527             {
  528                 timeCrc = UPDC32 (((unsigned char *) &dwTimer)[i], timeCrc);
  529             }
  530 
  531             EnterCriticalSection (&critRandProt);
  532             /* only count real mouse messages in entropy estimation */
  533             if (    (nCode == HC_ACTION) && (wParam == WM_MOUSEMOVE)
  534                 && ((pt.x != lastPoint.x) || (pt.y != lastPoint.y)))
  535             {
  536                 ProcessedMouseEventsCounter++;
  537                 lastPoint = pt;
  538             }
  539             RandaddInt32 ((unsigned __int32) (crc + timeCrc));
  540             LeaveCriticalSection (&critRandProt);
  541         }
  542         lastCrc2 = lastCrc;
  543         lastCrc = crc;
  544 
  545     }
  546     return 0;
  547 }
  548 
  549 /* Capture the keyboard, as long as the event is not the same as the last two
  550    events, add the crc of the event to the pool along with the crc of the time
  551    difference between this event and the last. The role of CRC-32 is merely to
  552    perform diffusion. Note that the output of CRC-32 is subsequently processed
  553    using a cryptographically secure hash algorithm.  */
  554 LRESULT CALLBACK KeyboardProc (int nCode, WPARAM wParam, LPARAM lParam)
  555 {
  556     static int lLastKey, lLastKey2;
  557     static DWORD dwLastTimer;
  558     int nKey = (lParam & 0x00ff0000) >> 16;
  559     int nCapture = 0;
  560 
  561     if (nCode < 0)
  562         return CallNextHookEx (hMouse, nCode, wParam, lParam);
  563 
  564     if ((lParam & 0x0000ffff) == 1 && !(lParam & 0x20000000) &&
  565         (lParam & 0x80000000))
  566     {
  567         if (nKey != lLastKey)
  568             nCapture = 1;   /* Capture this key */
  569         else if (nKey != lLastKey2)
  570             nCapture = 1;   /* Allow for one repeat */
  571     }
  572     if (nCapture)
  573     {
  574         DWORD dwTimer = GetTickCount ();
  575         DWORD j = dwLastTimer - dwTimer;
  576         unsigned __int32 timeCrc = 0L;
  577         int i;
  578 
  579         dwLastTimer = dwTimer;
  580         lLastKey2 = lLastKey;
  581         lLastKey = nKey;
  582 
  583         for (i = 0; i < 4; i++)
  584         {
  585             timeCrc = UPDC32 (((unsigned char *) &j)[i], timeCrc);
  586         }
  587 
  588         for (i = 0; i < 4; i++)
  589         {
  590             timeCrc = UPDC32 (((unsigned char *) &dwTimer)[i], timeCrc);
  591         }
  592 
  593         EnterCriticalSection (&critRandProt);
  594         RandaddInt32 ((unsigned __int32) (GetCrc32((unsigned char*) &lParam, sizeof(lParam)) + timeCrc));
  595         LeaveCriticalSection (&critRandProt);
  596     }
  597 
  598     return CallNextHookEx (hMouse, nCode, wParam, lParam);
  599 }
  600 
  601 /* This is the thread function which will poll the system for randomness */
  602 static unsigned __stdcall PeriodicFastPollThreadProc (void *dummy)
  603 {
  604     UNREFERENCED_PARAMETER (dummy);     /* Remove unused parameter warning */
  605 
  606     for (;;)
  607     {
  608         EnterCriticalSection (&critRandProt);
  609 
  610         if (bThreadTerminate)
  611         {
  612             bThreadTerminate = FALSE;
  613             LeaveCriticalSection (&critRandProt);
  614             _endthreadex (0);
  615         }
  616         else if (bFastPollEnabled)
  617         {
  618             FastPoll ();
  619         }
  620 
  621         LeaveCriticalSection (&critRandProt);
  622 
  623         Sleep (FASTPOLL_INTERVAL);
  624     }
  625 }
  626 
  627 /* Type definitions for function pointers to call NetAPI32 functions */
  628 
  629 typedef
  630   DWORD (WINAPI * NETSTATISTICSGET) (LPWSTR szServer, LPWSTR szService,
  631                      DWORD dwLevel, DWORD dwOptions,
  632                      LPBYTE * lpBuffer);
  633 typedef
  634   DWORD (WINAPI * NETAPIBUFFERSIZE) (LPVOID lpBuffer, LPDWORD cbBuffer);
  635 typedef
  636   DWORD (WINAPI * NETAPIBUFFERFREE) (LPVOID lpBuffer);
  637 
  638 NETSTATISTICSGET pNetStatisticsGet = NULL;
  639 NETAPIBUFFERSIZE pNetApiBufferSize = NULL;
  640 NETAPIBUFFERFREE pNetApiBufferFree = NULL;
  641 
  642 
  643 /* This is the slowpoll function which gathers up network/hard drive
  644    performance data for the random pool */
  645 BOOL SlowPoll (void)
  646 {
  647     static int isWorkstation = -1;
  648     static int cbPerfData = 0x10000;
  649     HANDLE hDevice;
  650     LPBYTE lpBuffer;
  651     DWORD dwSize, status;
  652     LPWSTR lpszLanW, lpszLanS;
  653     int nDrive;
  654 
  655     /* Find out whether this is an NT server or workstation if necessary */
  656     if (isWorkstation == -1)
  657     {
  658         HKEY hKey;
  659 
  660         if (RegOpenKeyEx (HKEY_LOCAL_MACHINE,
  661                L"SYSTEM\\CurrentControlSet\\Control\\ProductOptions",
  662                   0, KEY_READ, &hKey) == ERROR_SUCCESS)
  663         {
  664             wchar_t szValue[32];
  665             dwSize = sizeof (szValue);
  666 
  667             isWorkstation = TRUE;
  668             status = RegQueryValueEx (hKey, L"ProductType", 0, NULL,
  669                           (LPBYTE) szValue, &dwSize);
  670 
  671             if (status == ERROR_SUCCESS && _wcsicmp (szValue, L"WinNT"))
  672                 /* Note: There are (at least) three cases for
  673                    ProductType: WinNT = NT Workstation,
  674                    ServerNT = NT Server, LanmanNT = NT Server
  675                    acting as a Domain Controller */
  676                 isWorkstation = FALSE;
  677 
  678             RegCloseKey (hKey);
  679         }
  680     }
  681     /* Initialize the NetAPI32 function pointers if necessary */
  682     if (hNetAPI32 == NULL)
  683     {
  684         /* Obtain a handle to the module containing the Lan Manager
  685            functions */
  686         wchar_t dllPath[MAX_PATH];
  687         if (GetSystemDirectory (dllPath, MAX_PATH))
  688         {
  689             StringCchCatW(dllPath, ARRAYSIZE(dllPath), L"\\NETAPI32.DLL");
  690         }
  691         else
  692             StringCchCopyW(dllPath, ARRAYSIZE(dllPath), L"C:\\Windows\\System32\\NETAPI32.DLL");
  693 
  694         hNetAPI32 = LoadLibrary (dllPath);
  695         if (hNetAPI32 != NULL)
  696         {
  697             /* Now get pointers to the functions */
  698             pNetStatisticsGet = (NETSTATISTICSGET) GetProcAddress (hNetAPI32,
  699                             "NetStatisticsGet");
  700             pNetApiBufferSize = (NETAPIBUFFERSIZE) GetProcAddress (hNetAPI32,
  701                             "NetApiBufferSize");
  702             pNetApiBufferFree = (NETAPIBUFFERFREE) GetProcAddress (hNetAPI32,
  703                             "NetApiBufferFree");
  704 
  705             /* Make sure we got valid pointers for every NetAPI32
  706                function */
  707             if (pNetStatisticsGet == NULL ||
  708                 pNetApiBufferSize == NULL ||
  709                 pNetApiBufferFree == NULL)
  710             {
  711                 /* Free the library reference and reset the
  712                    static handle */
  713                 FreeLibrary (hNetAPI32);
  714                 hNetAPI32 = NULL;
  715             }
  716         }
  717     }
  718 
  719     /* Get network statistics.  Note: Both NT Workstation and NT Server
  720        by default will be running both the workstation and server
  721        services.  The heuristic below is probably useful though on the
  722        assumption that the majority of the network traffic will be via
  723        the appropriate service */
  724     lpszLanW = (LPWSTR) WIDE ("LanmanWorkstation");
  725     lpszLanS = (LPWSTR) WIDE ("LanmanServer");
  726     if (hNetAPI32 &&
  727         pNetStatisticsGet (NULL,
  728                    isWorkstation ? lpszLanW : lpszLanS,
  729                    0, 0, &lpBuffer) == 0)
  730     {
  731         pNetApiBufferSize (lpBuffer, &dwSize);
  732         RandaddBuf ((unsigned char *) lpBuffer, dwSize);
  733         pNetApiBufferFree (lpBuffer);
  734     }
  735 
  736     /* Get disk I/O statistics for all the hard drives */
  737     for (nDrive = 0;; nDrive++)
  738     {
  739         DISK_PERFORMANCE diskPerformance;
  740         wchar_t szDevice[24];
  741 
  742         /* Check whether we can access this device */
  743         StringCchPrintfW (szDevice, ARRAYSIZE(szDevice), L"\\\\.\\PhysicalDrive%d", nDrive);
  744         hDevice = CreateFile (szDevice, 0, FILE_SHARE_READ | FILE_SHARE_WRITE,
  745                       NULL, OPEN_EXISTING, 0, NULL);
  746         if (hDevice == INVALID_HANDLE_VALUE)
  747             break;
  748 
  749 
  750         /* Note: This only works if you have turned on the disk
  751            performance counters with 'diskperf -y'.  These counters
  752            are off by default */
  753         if (DeviceIoControl (hDevice, IOCTL_DISK_PERFORMANCE, NULL, 0,
  754                 &diskPerformance, sizeof (DISK_PERFORMANCE),
  755                      &dwSize, NULL))
  756         {
  757             RandaddBuf ((unsigned char *) &diskPerformance, dwSize);
  758         }
  759         CloseHandle (hDevice);
  760     }
  761 
  762     // CryptoAPI: We always have a valid CryptoAPI context when we arrive here but
  763     //            we keep the check for clarity purpose
  764     if ( !CryptoAPIAvailable )
  765         return FALSE;
  766     if (CryptGenRandom (hCryptProv, sizeof (buffer), buffer))
  767     {
  768         RandaddBuf (buffer, sizeof (buffer));
  769 
  770         burn(buffer, sizeof (buffer));
  771         Randmix();
  772         return TRUE;
  773     }
  774     else
  775     {
  776         /* return error in case CryptGenRandom fails */
  777         CryptoAPILastError = GetLastError ();
  778         return FALSE;
  779     }
  780 }
  781 
  782 
  783 /* This is the fastpoll function which gathers up info by calling various api's */
  784 BOOL FastPoll (void)
  785 {
  786     int nOriginalRandIndex = nRandIndex;
  787     static BOOL addedFixedItems = FALSE;
  788     FILETIME creationTime, exitTime, kernelTime, userTime;
  789     SIZE_T minimumWorkingSetSize, maximumWorkingSetSize;
  790     LARGE_INTEGER performanceCount;
  791     MEMORYSTATUS memoryStatus;
  792     HANDLE handle;
  793     POINT point;
  794 
  795     /* Get various basic pieces of system information */
  796     RandaddIntPtr (GetActiveWindow ()); /* Handle of active window */
  797     RandaddIntPtr (GetCapture ());  /* Handle of window with mouse
  798                        capture */
  799     RandaddIntPtr (GetClipboardOwner ());   /* Handle of clipboard owner */
  800     RandaddIntPtr (GetClipboardViewer ());  /* Handle of start of
  801                            clpbd.viewer list */
  802     RandaddIntPtr (GetCurrentProcess ());   /* Pseudohandle of current
  803                            process */
  804     RandaddInt32 (GetCurrentProcessId ());  /* Current process ID */
  805     RandaddIntPtr (GetCurrentThread ());    /* Pseudohandle of current
  806                            thread */
  807     RandaddInt32 (GetCurrentThreadId ());   /* Current thread ID */
  808     RandaddInt32 (GetCurrentTime ());   /* Milliseconds since Windows
  809                            started */
  810     RandaddIntPtr (GetDesktopWindow ());    /* Handle of desktop window */
  811     RandaddIntPtr (GetFocus ());    /* Handle of window with kb.focus */
  812     RandaddInt32 (GetInputState ());    /* Whether sys.queue has any events */
  813     RandaddInt32 (GetMessagePos ());    /* Cursor pos.for last message */
  814     RandaddInt32 (GetMessageTime ());   /* 1 ms time for last message */
  815     RandaddIntPtr (GetOpenClipboardWindow ());  /* Handle of window with
  816                                clpbd.open */
  817     RandaddIntPtr (GetProcessHeap ());  /* Handle of process heap */
  818     RandaddIntPtr (GetProcessWindowStation ()); /* Handle of procs
  819                                window station */
  820     RandaddInt32 (GetQueueStatus (QS_ALLEVENTS));   /* Types of events in
  821                                input queue */
  822 
  823     /* Get multiword system information */
  824     GetCaretPos (&point);   /* Current caret position */
  825     RandaddBuf ((unsigned char *) &point, sizeof (POINT));
  826     GetCursorPos (&point);  /* Current mouse cursor position */
  827     RandaddBuf ((unsigned char *) &point, sizeof (POINT));
  828 
  829     /* Get percent of memory in use, bytes of physical memory, bytes of
  830        free physical memory, bytes in paging file, free bytes in paging
  831        file, user bytes of address space, and free user bytes */
  832     memoryStatus.dwLength = sizeof (MEMORYSTATUS);
  833     GlobalMemoryStatus (&memoryStatus);
  834     RandaddBuf ((unsigned char *) &memoryStatus, sizeof (MEMORYSTATUS));
  835 
  836     /* Get thread and process creation time, exit time, time in kernel
  837        mode, and time in user mode in 100ns intervals */
  838     handle = GetCurrentThread ();
  839     GetThreadTimes (handle, &creationTime, &exitTime, &kernelTime, &userTime);
  840     RandaddBuf ((unsigned char *) &creationTime, sizeof (FILETIME));
  841     RandaddBuf ((unsigned char *) &exitTime, sizeof (FILETIME));
  842     RandaddBuf ((unsigned char *) &kernelTime, sizeof (FILETIME));
  843     RandaddBuf ((unsigned char *) &userTime, sizeof (FILETIME));
  844     handle = GetCurrentProcess ();
  845     GetProcessTimes (handle, &creationTime, &exitTime, &kernelTime, &userTime);
  846     RandaddBuf ((unsigned char *) &creationTime, sizeof (FILETIME));
  847     RandaddBuf ((unsigned char *) &exitTime, sizeof (FILETIME));
  848     RandaddBuf ((unsigned char *) &kernelTime, sizeof (FILETIME));
  849     RandaddBuf ((unsigned char *) &userTime, sizeof (FILETIME));
  850 
  851     /* Get the minimum and maximum working set size for the current
  852        process */
  853     GetProcessWorkingSetSize (handle, &minimumWorkingSetSize,
  854                   &maximumWorkingSetSize);
  855     RandaddIntPtr (minimumWorkingSetSize);
  856     RandaddIntPtr (maximumWorkingSetSize);
  857 
  858     /* The following are fixed for the lifetime of the process so we only
  859        add them once */
  860     if (addedFixedItems == 0)
  861     {
  862         STARTUPINFO startupInfo;
  863 
  864         /* Get name of desktop, console window title, new window
  865            position and size, window flags, and handles for stdin,
  866            stdout, and stderr */
  867         startupInfo.cb = sizeof (STARTUPINFO);
  868         GetStartupInfo (&startupInfo);
  869         RandaddBuf ((unsigned char *) &startupInfo, sizeof (STARTUPINFO));
  870         addedFixedItems = TRUE;
  871     }
  872     /* The docs say QPC can fail if appropriate hardware is not
  873        available. It works on 486 & Pentium boxes, but hasn't been tested
  874        for 386 or RISC boxes */
  875     if (QueryPerformanceCounter (&performanceCount))
  876         RandaddBuf ((unsigned char *) &performanceCount, sizeof (LARGE_INTEGER));
  877     else
  878     {
  879         /* Millisecond accuracy at best... */
  880         DWORD dwTicks = GetTickCount ();
  881         RandaddBuf ((unsigned char *) &dwTicks, sizeof (dwTicks));
  882     }
  883 
  884     // CryptoAPI: We always have a valid CryptoAPI context when we arrive here but
  885     //            we keep the check for clarity purpose
  886     if ( !CryptoAPIAvailable )
  887         return FALSE;
  888     if (CryptGenRandom (hCryptProv, sizeof (buffer), buffer))
  889     {
  890         RandaddBuf (buffer, sizeof (buffer));
  891         burn (buffer, sizeof(buffer));
  892     }
  893     else
  894     {
  895         /* return error in case CryptGenRandom fails */
  896         CryptoAPILastError = GetLastError ();
  897         return FALSE;
  898     }
  899 
  900     /* Apply the pool mixing function */
  901     Randmix();
  902 
  903     /* Restore the original pool cursor position. If this wasn't done, mouse coordinates
  904        could be written to a limited area of the pool, especially when moving the mouse
  905        uninterruptedly. The severity of the problem would depend on the length of data
  906        written by FastPoll (if it was equal to the size of the pool, mouse coordinates
  907        would be written only to a particular 4-byte area, whenever moving the mouse
  908        uninterruptedly). */
  909     nRandIndex = nOriginalRandIndex;
  910 
  911     return TRUE;
  912 }
  913