VeraCrypt
aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMounir IDRASSI <mounir.idrassi@idrix.fr>2025-02-02 13:51:33 +0100
committerMounir IDRASSI <mounir.idrassi@idrix.fr>2025-02-02 13:51:33 +0100
commit04e7d8c5ee563dc0b72a030c57d1a2fa28133e87 (patch)
tree1e44f4e8f44dea2db13cff3620b8088e46ee07fa /src
parent498dff9013d18e5978ab77c14ea2b2d0229603a4 (diff)
downloadVeraCrypt-04e7d8c5ee563dc0b72a030c57d1a2fa28133e87.tar.gz
VeraCrypt-04e7d8c5ee563dc0b72a030c57d1a2fa28133e87.zip
Windows: Revert use PDH API to gather system entropy because of issues encountered by users
cf thread: https://sourceforge.net/p/veracrypt/discussion/general/thread/293d401a30 delays and sporadic crashes in some cases.
Diffstat (limited to 'src')
-rw-r--r--src/Common/Random.c346
1 files changed, 134 insertions, 212 deletions
diff --git a/src/Common/Random.c b/src/Common/Random.c
index 10995f74..4c6382b4 100644
--- a/src/Common/Random.c
+++ b/src/Common/Random.c
@@ -20,8 +20,6 @@
#include "Crypto\rdrand.h"
#include <Strsafe.h>
#include <bcrypt.h>
-#include <pdh.h>
-#include <pdhmsg.h>
static unsigned __int8 buffer[RNG_POOL_SIZE];
static unsigned char *pRandPool = NULL;
@@ -84,45 +82,15 @@ DWORD ProcessedMouseEventsCounter = 0;
CRITICAL_SECTION critRandProt; /* The critical section */
BOOL volatile bThreadTerminate = FALSE; /* This variable is shared among thread's so its made volatile */
+/* Network library handle for the SlowPoll function */
+HANDLE hNetAPI32 = NULL;
+
// CryptoAPI
DWORD CryptoAPILastError = ERROR_SUCCESS;
typedef DWORD (WINAPI *RtlNtStatusToDosError_t)(NTSTATUS);
RtlNtStatusToDosError_t pRtlNtStatusToDosError = NULL;
-static HMODULE hPdhLib = NULL;
-
-typedef PDH_STATUS (WINAPI *PfnPdhOpenQueryW)(LPCWSTR, DWORD_PTR, PDH_HQUERY *);
-typedef PDH_STATUS (WINAPI *PfnPdhAddCounterW)(PDH_HQUERY, LPCWSTR, DWORD_PTR, PDH_HCOUNTER *);
-typedef PDH_STATUS (WINAPI *PfnPdhCollectQueryData)(PDH_HQUERY);
-typedef PDH_STATUS (WINAPI *PfnPdhGetFormattedCounterValue)(PDH_HCOUNTER, DWORD, LPDWORD, PPDH_FMT_COUNTERVALUE);
-typedef PDH_STATUS (WINAPI *PfnPdhCloseQuery)(PDH_HQUERY);
-
-static PfnPdhOpenQueryW pfnPdhOpenQuery = NULL;
-static PfnPdhAddCounterW pfnPdhAddCounter = NULL;
-static PfnPdhCollectQueryData pfnPdhCollectQueryData = NULL;
-static PfnPdhGetFormattedCounterValue pfnPdhGetFormattedCounterValue = NULL;
-static PfnPdhCloseQuery pfnPdhCloseQuery = NULL;
-
-static BOOL LoadPdhDll()
-{
- if (!hPdhLib)
- {
- hPdhLib = LoadLibraryExW(L"pdh.dll", NULL, LOAD_LIBRARY_SEARCH_SYSTEM32);
- if (!hPdhLib)
- return FALSE;
-
- pfnPdhOpenQuery = (PfnPdhOpenQueryW) GetProcAddress(hPdhLib, "PdhOpenQueryW");
- pfnPdhAddCounter = (PfnPdhAddCounterW) GetProcAddress(hPdhLib, "PdhAddCounterW");
- pfnPdhCollectQueryData = (PfnPdhCollectQueryData) GetProcAddress(hPdhLib, "PdhCollectQueryData");
- pfnPdhGetFormattedCounterValue = (PfnPdhGetFormattedCounterValue) GetProcAddress(hPdhLib, "PdhGetFormattedCounterValue");
- pfnPdhCloseQuery = (PfnPdhCloseQuery) GetProcAddress(hPdhLib, "PdhCloseQuery");
- }
-
- return (pfnPdhOpenQuery && pfnPdhAddCounter && pfnPdhCollectQueryData &&
- pfnPdhGetFormattedCounterValue && pfnPdhCloseQuery);
-}
-
/* Init the random number generator, setup the hooks, and start the thread */
int RandinitWithCheck ( int* pAlreadyInitialized)
{
@@ -223,6 +191,12 @@ void RandStop (BOOL freePool)
if (PeriodicFastPollThreadHandle)
WaitForSingleObject (PeriodicFastPollThreadHandle, INFINITE);
+ if (hNetAPI32 != 0)
+ {
+ FreeLibrary (hNetAPI32);
+ hNetAPI32 = NULL;
+ }
+
hMouse = NULL;
hKeyboard = NULL;
@@ -280,7 +254,7 @@ BOOL Randmix ()
if (bRandmixEnabled)
{
unsigned char hashOutputBuffer [MAX_DIGESTSIZE];
- #ifndef WOLFCRYPT_BACKEND
+ #ifndef WOLFCRYPT_BACKEND
WHIRLPOOL_CTX wctx;
blake2s_state bctx;
STREEBOG_CTX stctx;
@@ -299,11 +273,11 @@ BOOL Randmix ()
digestSize = SHA256_DIGESTSIZE;
break;
- #ifndef WOLFCRYPT_BACKEND
+ #ifndef WOLFCRYPT_BACKEND
case BLAKE2S:
digestSize = BLAKE2S_DIGESTSIZE;
break;
-
+
case WHIRLPOOL:
digestSize = WHIRLPOOL_DIGESTSIZE;
break;
@@ -666,192 +640,142 @@ static unsigned __stdcall PeriodicFastPollThreadProc (void *dummy)
}
}
+/* Type definitions for function pointers to call NetAPI32 functions */
-/* -------------------------------------------------------------------------------------
- GetDiskStatistics: This function uses the Windows Performance Data Helper (PDH) API
- to collect disk statistics. The function collects the number of disk reads and writes
- per second for all physical disks. The function also collects high-resolution
- timestamps before and after the PDH query. The function then adds the collected data
- to the random pool.
- The code waits a short random interval between the two PDH samples to ensures that
- the performance counters have time to accumulate measurable changes and produce more
- varied data.
- -------------------------------------------------------------------------------------
+typedef
+ DWORD (WINAPI * NETSTATISTICSGET) (LPWSTR szServer, LPWSTR szService,
+ DWORD dwLevel, DWORD dwOptions,
+ LPBYTE * lpBuffer);
+typedef
+ DWORD (WINAPI * NETAPIBUFFERSIZE) (LPVOID lpBuffer, LPDWORD cbBuffer);
+typedef
+ DWORD (WINAPI * NETAPIBUFFERFREE) (LPVOID lpBuffer);
-*/
-void GetDiskStatistics()
-{
- if (!LoadPdhDll())
- return;
- PDH_STATUS status;
- PDH_HQUERY query = NULL;
- PDH_HCOUNTER counterReads = NULL, counterWrites = NULL;
- PDH_FMT_COUNTERVALUE counterValue;
- DWORD dwType;
- LONGLONG llReads = 0, llWrites = 0;
- DWORDLONG tstampBefore = 0, tstampAfter = 0;
- LARGE_INTEGER perfCounterBefore, perfCounterAfter;
-
- // High-resolution timestamps
- if (!QueryPerformanceCounter(&perfCounterBefore))
- return;
- tstampBefore = GetTickCount64();
-
- // Open PDH query
- status = pfnPdhOpenQuery(NULL, 0, &query);
- if (status != ERROR_SUCCESS)
- goto error;
-
- // Add counters for disk reads and writes (all physical disks).
- status = pfnPdhAddCounter(query, L"\\PhysicalDisk(*)\\Disk Reads/sec", 0, &counterReads);
- if (status != ERROR_SUCCESS)
- goto error;
-
- status = pfnPdhAddCounter(query, L"\\PhysicalDisk(*)\\Disk Writes/sec", 0, &counterWrites);
- if (status != ERROR_SUCCESS)
- goto error;
-
- // First sample
- status = pfnPdhCollectQueryData(query);
- if (status != ERROR_SUCCESS)
- goto error;
-
- // Wait a short random interval
- Sleep(10 + (GetCurrentProcessId() % 40));
-
- // Second sample
- status = pfnPdhCollectQueryData(query);
- if (status != ERROR_SUCCESS)
- goto error;
-
- // Format counters in PDH_FMT_LARGE
- status = pfnPdhGetFormattedCounterValue(counterReads, PDH_FMT_LARGE, &dwType, &counterValue);
- if (status == ERROR_SUCCESS)
- llReads = counterValue.largeValue;
-
- status = pfnPdhGetFormattedCounterValue(counterWrites, PDH_FMT_LARGE, &dwType, &counterValue);
- if (status == ERROR_SUCCESS)
- llWrites = counterValue.largeValue;
-
- // Another high-resolution timestamp
- if (!QueryPerformanceCounter(&perfCounterAfter))
- goto error;
- tstampAfter = GetTickCount64();
-
- // Close PDH query
- pfnPdhCloseQuery(query);
- query = NULL;
-
- // Collect results into the random pool
- RandaddBuf(&llReads, sizeof(llReads));
- RandaddBuf(&llWrites, sizeof(llWrites));
- RandaddBuf(&tstampBefore, sizeof(tstampBefore));
- RandaddBuf(&tstampAfter, sizeof(tstampAfter));
- RandaddBuf(&perfCounterBefore.QuadPart, sizeof(perfCounterBefore.QuadPart));
- RandaddBuf(&perfCounterAfter.QuadPart, sizeof(perfCounterAfter.QuadPart));
-
-error:
- if (query)
- pfnPdhCloseQuery(query);
-}
+NETSTATISTICSGET pNetStatisticsGet = NULL;
+NETAPIBUFFERSIZE pNetApiBufferSize = NULL;
+NETAPIBUFFERFREE pNetApiBufferFree = NULL;
-/* -------------------------------------------------------------------------------------
- GetNetworkStatistics: This function uses the Windows Performance Data Helper (PDH) API
- to collect network statistics. The function collects the number of bytes sent and
- received per second for all network interfaces. The function also collects
- high-resolution timestamps before and after the PDH query. The function then adds the
- collected data to the random pool.
- The code waits a short random interval between the two PDH samples to ensures that
- the performance counters have time to accumulate measurable changes and produce more
- varied data.
-*/
-void GetNetworkStatistics()
+/* This is the slowpoll function which gathers up network/hard drive
+ performance data for the random pool */
+BOOL SlowPoll (void)
{
- if (!LoadPdhDll())
- return;
- PDH_STATUS status;
- PDH_HQUERY query = NULL;
- PDH_HCOUNTER counterBytesSent = NULL, counterBytesReceived = NULL;
- PDH_FMT_COUNTERVALUE counterValue;
- DWORD dwType;
- LONGLONG llBytesSent = 0, llBytesReceived = 0;
- DWORDLONG tstampBefore = 0, tstampAfter = 0;
- LARGE_INTEGER perfCounterBefore, perfCounterAfter;
-
- // High-resolution timestamps
- if (!QueryPerformanceCounter(&perfCounterBefore))
- return;
- tstampBefore = GetTickCount64();
-
- // Open PDH query
- status = pfnPdhOpenQuery(NULL, 0, &query);
- if (status != ERROR_SUCCESS)
- goto error;
-
- // Add counters for network bytes sent and received
- status = pfnPdhAddCounter(query, L"\\Network Interface(*)\\Bytes Sent/sec", 0, &counterBytesSent);
- if (status != ERROR_SUCCESS)
- goto error;
-
- status = pfnPdhAddCounter(query, L"\\Network Interface(*)\\Bytes Received/sec", 0, &counterBytesReceived);
- if (status != ERROR_SUCCESS)
- goto error;
+ static int isWorkstation = -1;
+ static int cbPerfData = 0x10000;
+ HANDLE hDevice;
+ LPBYTE lpBuffer;
+ DWORD dwSize, status;
+ LPWSTR lpszLanW, lpszLanS;
+ int nDrive;
+ NTSTATUS bStatus = 0;
- // First sample
- status = pfnPdhCollectQueryData(query);
- if (status != ERROR_SUCCESS)
- goto error;
+ /* Find out whether this is an NT server or workstation if necessary */
+ if (isWorkstation == -1)
+ {
+ HKEY hKey;
- // Wait short, dynamic interval
- Sleep(10 + (GetCurrentProcessId() % 40));
+ if (RegOpenKeyEx (HKEY_LOCAL_MACHINE,
+ L"SYSTEM\\CurrentControlSet\\Control\\ProductOptions",
+ 0, KEY_READ, &hKey) == ERROR_SUCCESS)
+ {
+ wchar_t szValue[32];
+ dwSize = sizeof (szValue);
- // Second sample
- status = pfnPdhCollectQueryData(query);
- if (status != ERROR_SUCCESS)
- goto error;
+ isWorkstation = TRUE;
+ status = RegQueryValueEx (hKey, L"ProductType", 0, NULL,
+ (LPBYTE) szValue, &dwSize);
- // Format counters
- status = pfnPdhGetFormattedCounterValue(counterBytesSent, PDH_FMT_LARGE, &dwType, &counterValue);
- if (status == ERROR_SUCCESS)
- llBytesSent = counterValue.largeValue;
+ if (status == ERROR_SUCCESS && _wcsicmp (szValue, L"WinNT"))
+ /* Note: There are (at least) three cases for
+ ProductType: WinNT = NT Workstation,
+ ServerNT = NT Server, LanmanNT = NT Server
+ acting as a Domain Controller */
+ isWorkstation = FALSE;
- status = pfnPdhGetFormattedCounterValue(counterBytesReceived, PDH_FMT_LARGE, &dwType, &counterValue);
- if (status == ERROR_SUCCESS)
- llBytesReceived = counterValue.largeValue;
+ RegCloseKey (hKey);
+ }
+ }
+ /* Initialize the NetAPI32 function pointers if necessary */
+ if (hNetAPI32 == NULL)
+ {
+ /* Obtain a handle to the module containing the Lan Manager
+ functions */
+ wchar_t dllPath[MAX_PATH];
+ if (GetSystemDirectory (dllPath, MAX_PATH))
+ {
+ StringCchCatW(dllPath, ARRAYSIZE(dllPath), L"\\NETAPI32.DLL");
+ }
+ else
+ StringCchCopyW(dllPath, ARRAYSIZE(dllPath), L"C:\\Windows\\System32\\NETAPI32.DLL");
- if (!QueryPerformanceCounter(&perfCounterAfter))
- goto error;
- tstampAfter = GetTickCount64();
+ hNetAPI32 = LoadLibrary (dllPath);
+ if (hNetAPI32 != NULL)
+ {
+ /* Now get pointers to the functions */
+ pNetStatisticsGet = (NETSTATISTICSGET) GetProcAddress (hNetAPI32,
+ "NetStatisticsGet");
+ pNetApiBufferSize = (NETAPIBUFFERSIZE) GetProcAddress (hNetAPI32,
+ "NetApiBufferSize");
+ pNetApiBufferFree = (NETAPIBUFFERFREE) GetProcAddress (hNetAPI32,
+ "NetApiBufferFree");
+
+ /* Make sure we got valid pointers for every NetAPI32
+ function */
+ if (pNetStatisticsGet == NULL ||
+ pNetApiBufferSize == NULL ||
+ pNetApiBufferFree == NULL)
+ {
+ /* Free the library reference and reset the
+ static handle */
+ FreeLibrary (hNetAPI32);
+ hNetAPI32 = NULL;
+ }
+ }
+ }
- // Close PDH query
- pfnPdhCloseQuery(query);
- query = NULL;
+ /* Get network statistics. Note: Both NT Workstation and NT Server
+ by default will be running both the workstation and server
+ services. The heuristic below is probably useful though on the
+ assumption that the majority of the network traffic will be via
+ the appropriate service */
+ lpszLanW = (LPWSTR) WIDE ("LanmanWorkstation");
+ lpszLanS = (LPWSTR) WIDE ("LanmanServer");
+ if (hNetAPI32 &&
+ pNetStatisticsGet (NULL,
+ isWorkstation ? lpszLanW : lpszLanS,
+ 0, 0, &lpBuffer) == 0)
+ {
+ pNetApiBufferSize (lpBuffer, &dwSize);
+ RandaddBuf ((unsigned char *) lpBuffer, dwSize);
+ pNetApiBufferFree (lpBuffer);
+ }
- // Collect results into our random pool
- RandaddBuf(&llBytesSent, sizeof(llBytesSent));
- RandaddBuf(&llBytesReceived, sizeof(llBytesReceived));
- RandaddBuf(&tstampBefore, sizeof(tstampBefore));
- RandaddBuf(&tstampAfter, sizeof(tstampAfter));
- RandaddBuf(&perfCounterBefore.QuadPart, sizeof(perfCounterBefore.QuadPart));
- RandaddBuf(&perfCounterAfter.QuadPart, sizeof(perfCounterAfter.QuadPart));
+ /* Get disk I/O statistics for all the hard drives */
+ for (nDrive = 0;; nDrive++)
+ {
+ DISK_PERFORMANCE diskPerformance;
+ wchar_t szDevice[24];
+
+ /* Check whether we can access this device */
+ StringCchPrintfW (szDevice, ARRAYSIZE(szDevice), L"\\\\.\\PhysicalDrive%d", nDrive);
+ hDevice = CreateFile (szDevice, 0, FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL, OPEN_EXISTING, 0, NULL);
+ if (hDevice == INVALID_HANDLE_VALUE)
+ break;
-error:
- if (query)
- pfnPdhCloseQuery(query);
-}
-/* This is the slowpoll function which gathers up network/hard drive
- performance data for the random pool */
-BOOL SlowPoll (void)
-{
- NTSTATUS bStatus = 0;
+ /* Note: This only works if you have turned on the disk
+ performance counters with 'diskperf -y'. These counters
+ are off by default */
+ if (DeviceIoControl (hDevice, IOCTL_DISK_PERFORMANCE, NULL, 0,
+ &diskPerformance, sizeof (DISK_PERFORMANCE),
+ &dwSize, NULL))
+ {
+ RandaddBuf ((unsigned char *) &diskPerformance, dwSize);
+ }
+ CloseHandle (hDevice);
+ }
- // Gather disk stats via PDH
- GetDiskStatistics();
-
- // Gather network stats via PDH
- GetNetworkStatistics();
bStatus = BCryptGenRandom(NULL, buffer, sizeof(buffer), BCRYPT_USE_SYSTEM_PREFERRED_RNG);
if (NT_SUCCESS(bStatus))
@@ -880,7 +804,7 @@ BOOL SlowPoll (void)
#ifndef _M_ARM64
// use RDSEED or RDRAND from CPU as source of entropy if present
- if ( IsCpuRngEnabled() &&
+ if ( IsCpuRngEnabled() &&
( (HasRDSEED() && RDSEED_getBytes (buffer, sizeof (buffer)))
|| (HasRDRAND() && RDRAND_getBytes (buffer, sizeof (buffer)))
))
@@ -890,8 +814,6 @@ BOOL SlowPoll (void)
#endif
burn(buffer, sizeof (buffer));
-
- /* Mix the pool */
Randmix();
return TRUE;
@@ -1015,7 +937,7 @@ BOOL FastPoll (void)
#ifndef _M_ARM64
// use RDSEED or RDRAND from CPU as source of entropy if enabled
- if ( IsCpuRngEnabled() &&
+ if ( IsCpuRngEnabled() &&
( (HasRDSEED() && RDSEED_getBytes (buffer, sizeof (buffer)))
|| (HasRDRAND() && RDRAND_getBytes (buffer, sizeof (buffer)))
))