VeraCrypt
aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Common/Random.c328
1 files changed, 125 insertions, 203 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
@@ -3,42 +3,40 @@
derived from the source code of TrueCrypt 7.1a, which is
Copyright (c) 2003-2012 TrueCrypt Developers Association and which is
governed by the TrueCrypt License 3.0, also from the source code of
Encryption for the Masses 2.02a, which is Copyright (c) 1998-2000 Paul Le Roux
and which is governed by the 'License Agreement for Encryption for the Masses'
Modifications and additions to the original source code (contained in this file)
and all other portions of this file are Copyright (c) 2013-2025 IDRIX
and are governed by the Apache License 2.0 the full text of which is
contained in the file License.txt included in VeraCrypt binary and source
code distribution packages. */
#include "Tcdefs.h"
#include "Crc.h"
#include "Random.h"
#include "Dlgcode.h"
#include "Crypto\cpu.h"
#include "Crypto\jitterentropy.h"
#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;
static BOOL bRandDidInit = FALSE;
static int nRandIndex = 0, randPoolReadIndex = 0;
static int HashFunction = DEFAULT_HASH_ALGORITHM;
static BOOL bDidSlowPoll = FALSE;
BOOL volatile bFastPollEnabled = TRUE; /* Used to reduce CPU load when performing benchmarks */
BOOL volatile bRandmixEnabled = TRUE; /* Used to reduce CPU load when performing benchmarks */
static BOOL RandomPoolEnrichedByUser = FALSE;
static HANDLE PeriodicFastPollThreadHandle = NULL;
/* Macro to add a single byte to the pool */
#define RandaddByte(x) {\
if (nRandIndex == RNG_POOL_SIZE) nRandIndex = 0;\
pRandPool[nRandIndex] = (unsigned char) ((unsigned char)x + pRandPool[nRandIndex]); \
if (nRandIndex % RANDMIX_BYTE_INTERVAL == 0) Randmix();\
nRandIndex++; \
}
@@ -67,79 +65,49 @@ void RandAddInt64 (unsigned __int64 x)
RandaddByte((x >> 48));
RandaddByte((x >> 56));
}
#include <tlhelp32.h>
#include "Dlgcode.h"
#ifndef SRC_POS
#define SRC_POS (__FUNCTION__ ":" TC_TO_STRING(__LINE__))
#endif
HHOOK hMouse = NULL; /* Mouse hook for the random number generator */
HHOOK hKeyboard = NULL; /* Keyboard hook for the random number generator */
DWORD ProcessedMouseEventsCounter = 0;
/* Variables for thread control, the thread is used to gather up info about
the system in in the background */
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)
{
BOOL bIgnoreHookError = FALSE;
DWORD dwLastError = ERROR_SUCCESS;
HMODULE ntdll;
if (GetMaxPkcs5OutSize() > RNG_POOL_SIZE)
TC_THROW_FATAL_EXCEPTION;
if(bRandDidInit)
{
if (pAlreadyInitialized)
*pAlreadyInitialized = 1;
return 0;
}
if (pAlreadyInitialized)
*pAlreadyInitialized = 0;
InitializeCriticalSection (&critRandProt);
@@ -206,40 +174,46 @@ void RandStop (BOOL freePool)
if (!bRandDidInit && freePool && pRandPool)
goto freePool;
if (bRandDidInit == FALSE)
return;
EnterCriticalSection (&critRandProt);
if (hMouse != 0)
UnhookWindowsHookEx (hMouse);
if (hKeyboard != 0)
UnhookWindowsHookEx (hKeyboard);
bThreadTerminate = TRUE;
LeaveCriticalSection (&critRandProt);
if (PeriodicFastPollThreadHandle)
WaitForSingleObject (PeriodicFastPollThreadHandle, INFINITE);
+ if (hNetAPI32 != 0)
+ {
+ FreeLibrary (hNetAPI32);
+ hNetAPI32 = NULL;
+ }
+
hMouse = NULL;
hKeyboard = NULL;
bThreadTerminate = FALSE;
DeleteCriticalSection (&critRandProt);
bRandDidInit = FALSE;
freePool:
if (freePool)
{
bDidSlowPoll = FALSE;
RandomPoolEnrichedByUser = FALSE;
if (pRandPool != NULL)
{
burn (pRandPool, RANDOMPOOL_ALLOCSIZE);
_aligned_free (pRandPool);
pRandPool = NULL;
}
@@ -649,266 +623,214 @@ static unsigned __stdcall PeriodicFastPollThreadProc (void *dummy)
{
EnterCriticalSection (&critRandProt);
if (bThreadTerminate)
{
bThreadTerminate = FALSE;
LeaveCriticalSection (&critRandProt);
_endthreadex (0);
}
else if (bFastPollEnabled)
{
FastPoll ();
}
LeaveCriticalSection (&critRandProt);
Sleep (FASTPOLL_INTERVAL);
}
}
+/* 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();
+NETSTATISTICSGET pNetStatisticsGet = NULL;
+NETAPIBUFFERSIZE pNetApiBufferSize = NULL;
+NETAPIBUFFERFREE pNetApiBufferFree = NULL;
- // 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;
+/* This is the slowpoll function which gathers up network/hard drive
+ performance data for the random pool */
+BOOL SlowPoll (void)
+{
+ static int isWorkstation = -1;
+ static int cbPerfData = 0x10000;
+ HANDLE hDevice;
+ LPBYTE lpBuffer;
+ DWORD dwSize, status;
+ LPWSTR lpszLanW, lpszLanS;
+ int nDrive;
+ NTSTATUS bStatus = 0;
- status = pfnPdhGetFormattedCounterValue(counterWrites, PDH_FMT_LARGE, &dwType, &counterValue);
- if (status == ERROR_SUCCESS)
- llWrites = counterValue.largeValue;
+ /* Find out whether this is an NT server or workstation if necessary */
+ if (isWorkstation == -1)
+ {
+ HKEY hKey;
- // Another high-resolution timestamp
- if (!QueryPerformanceCounter(&perfCounterAfter))
- goto error;
- tstampAfter = GetTickCount64();
+ if (RegOpenKeyEx (HKEY_LOCAL_MACHINE,
+ L"SYSTEM\\CurrentControlSet\\Control\\ProductOptions",
+ 0, KEY_READ, &hKey) == ERROR_SUCCESS)
+ {
+ wchar_t szValue[32];
+ dwSize = sizeof (szValue);
- // Close PDH query
- pfnPdhCloseQuery(query);
- query = NULL;
+ isWorkstation = TRUE;
+ status = RegQueryValueEx (hKey, L"ProductType", 0, NULL,
+ (LPBYTE) szValue, &dwSize);
- // 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));
+ 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;
-error:
- if (query)
- pfnPdhCloseQuery(query);
+ RegCloseKey (hKey);
}
-
-
-/* -------------------------------------------------------------------------------------
- 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()
+ }
+ /* Initialize the NetAPI32 function pointers if necessary */
+ if (hNetAPI32 == NULL)
{
- 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;
-
- // First sample
- status = pfnPdhCollectQueryData(query);
- if (status != ERROR_SUCCESS)
- goto error;
-
- // Wait short, dynamic interval
- Sleep(10 + (GetCurrentProcessId() % 40));
-
- // Second sample
- status = pfnPdhCollectQueryData(query);
- if (status != ERROR_SUCCESS)
- goto error;
+ /* 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");
- // Format counters
- status = pfnPdhGetFormattedCounterValue(counterBytesSent, PDH_FMT_LARGE, &dwType, &counterValue);
- if (status == ERROR_SUCCESS)
- llBytesSent = counterValue.largeValue;
+ 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");
- status = pfnPdhGetFormattedCounterValue(counterBytesReceived, PDH_FMT_LARGE, &dwType, &counterValue);
- if (status == ERROR_SUCCESS)
- llBytesReceived = counterValue.largeValue;
+ /* 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;
+ }
+ }
+ }
- if (!QueryPerformanceCounter(&perfCounterAfter))
- goto error;
- tstampAfter = GetTickCount64();
+ /* 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);
+ }
- // Close PDH query
- pfnPdhCloseQuery(query);
- query = NULL;
+ /* Get disk I/O statistics for all the hard drives */
+ for (nDrive = 0;; nDrive++)
+ {
+ DISK_PERFORMANCE diskPerformance;
+ wchar_t szDevice[24];
- // 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));
+ /* 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)
+ /* 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))
{
- NTSTATUS bStatus = 0;
-
- // Gather disk stats via PDH
- GetDiskStatistics();
+ RandaddBuf ((unsigned char *) &diskPerformance, dwSize);
+ }
+ CloseHandle (hDevice);
+ }
- // Gather network stats via PDH
- GetNetworkStatistics();
bStatus = BCryptGenRandom(NULL, buffer, sizeof(buffer), BCRYPT_USE_SYSTEM_PREFERRED_RNG);
if (NT_SUCCESS(bStatus))
{
RandaddBuf (buffer, sizeof (buffer));
}
else
{
/* return error in case BCryptGenRandom fails */
CryptoAPILastError = pRtlNtStatusToDosError (bStatus);
return FALSE;
}
/* use JitterEntropy library to get good quality random bytes based on CPU timing jitter */
if (0 == jent_entropy_init ())
{
struct rand_data *ec = jent_entropy_collector_alloc (1, 0);
if (ec)
{
ssize_t rndLen = jent_read_entropy (ec, (char*) buffer, sizeof (buffer));
if (rndLen > 0)
RandaddBuf (buffer, (int) rndLen);
jent_entropy_collector_free (ec);
}
}
#ifndef _M_ARM64
// use RDSEED or RDRAND from CPU as source of entropy if present
if ( IsCpuRngEnabled() &&
( (HasRDSEED() && RDSEED_getBytes (buffer, sizeof (buffer)))
|| (HasRDRAND() && RDRAND_getBytes (buffer, sizeof (buffer)))
))
{
RandaddBuf (buffer, sizeof (buffer));
}
#endif
burn(buffer, sizeof (buffer));
-
- /* Mix the pool */
Randmix();
return TRUE;
}
/* This is the fastpoll function which gathers up info by calling various api's */
BOOL FastPoll (void)
{
int nOriginalRandIndex = nRandIndex;
static BOOL addedFixedItems = FALSE;
FILETIME creationTime, exitTime, kernelTime, userTime;
SIZE_T minimumWorkingSetSize, maximumWorkingSetSize;
LARGE_INTEGER performanceCount;
MEMORYSTATUSEX memoryStatus;
HANDLE handle;
POINT point;
NTSTATUS bStatus = 0;
/* Get various basic pieces of system information */