VeraCrypt
aboutsummaryrefslogtreecommitdiff
path: root/src/Common/Random.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/Common/Random.c')
-rw-r--r--src/Common/Random.c48
1 files changed, 21 insertions, 27 deletions
diff --git a/src/Common/Random.c b/src/Common/Random.c
index ee3fcf53..0be4d601 100644
--- a/src/Common/Random.c
+++ b/src/Common/Random.c
@@ -1,51 +1,52 @@
/*
Legal Notice: Some portions of the source code contained in this file were
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-2017 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>
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++; \
}
/* Macro to add four bytes to the pool */
#define RandaddInt32(x) RandAddInt((unsigned __int32)x);
#ifdef _WIN64
#define RandaddIntPtr(x) RandAddInt64((unsigned __int64)x);
#else
#define RandaddIntPtr(x) RandAddInt((unsigned __int32)x);
#endif
void RandAddInt (unsigned __int32 x)
@@ -62,176 +63,171 @@ void RandAddInt64 (unsigned __int64 x)
RandaddByte((x >> 8));
RandaddByte((x >> 16));
RandaddByte((x >> 24));
RandaddByte((x >> 32));
RandaddByte((x >> 40));
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
-BOOL CryptoAPIAvailable = FALSE;
DWORD CryptoAPILastError = ERROR_SUCCESS;
-HCRYPTPROV hCryptProv;
+typedef DWORD (WINAPI *RtlNtStatusToDosError_t)(NTSTATUS);
+RtlNtStatusToDosError_t pRtlNtStatusToDosError = NULL;
/* 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);
bRandDidInit = TRUE;
CryptoAPILastError = ERROR_SUCCESS;
ProcessedMouseEventsCounter = 0;
if (pRandPool == NULL)
{
pRandPool = (unsigned char *) _aligned_malloc (RANDOMPOOL_ALLOCSIZE, 16);
if (pRandPool == NULL)
goto error;
bDidSlowPoll = FALSE;
RandomPoolEnrichedByUser = FALSE;
memset (pRandPool, 0, RANDOMPOOL_ALLOCSIZE);
VirtualLock (pRandPool, RANDOMPOOL_ALLOCSIZE);
}
bIgnoreHookError = IsThreadInSecureDesktop(GetCurrentThreadId());
hKeyboard = SetWindowsHookEx (WH_KEYBOARD, (HOOKPROC)&KeyboardProc, NULL, GetCurrentThreadId ());
if (hKeyboard == 0 && !bIgnoreHookError) handleWin32Error (0, SRC_POS);
hMouse = SetWindowsHookEx (WH_MOUSE, (HOOKPROC)&MouseProc, NULL, GetCurrentThreadId ());
if (hMouse == 0 && !bIgnoreHookError)
{
handleWin32Error (0, SRC_POS);
goto error;
}
- if (!CryptAcquireContext (&hCryptProv, NULL, MS_ENHANCED_PROV, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT | CRYPT_SILENT))
- {
- CryptoAPIAvailable = FALSE;
- CryptoAPILastError = GetLastError ();
+ ntdll = GetModuleHandleW(L"ntdll.dll");
+ if (!ntdll) {
+ // If ntdll.dll is not found, return a fallback error code
+ CryptoAPILastError = ERROR_MOD_NOT_FOUND;
goto error;
}
else
- CryptoAPIAvailable = TRUE;
+ pRtlNtStatusToDosError = (RtlNtStatusToDosError_t)GetProcAddress(ntdll, "RtlNtStatusToDosError");
if (!(PeriodicFastPollThreadHandle = (HANDLE) _beginthreadex (NULL, 0, PeriodicFastPollThreadProc, NULL, 0, NULL)))
goto error;
return 0;
error:
dwLastError = GetLastError();
RandStop (TRUE);
SetLastError (dwLastError);
return 1;
}
int Randinit ()
{
return RandinitWithCheck (NULL);
}
/* Close everything down, including the thread which is closed down by
setting a flag which eventually causes the thread function to exit */
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;
}
- if (CryptoAPIAvailable)
- {
- CryptReleaseContext (hCryptProv, 0);
- CryptoAPIAvailable = FALSE;
- CryptoAPILastError = ERROR_SUCCESS;
- }
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;
}
}
}
BOOL IsRandomNumberGeneratorStarted ()
{
return bRandDidInit;
}
void RandSetHashFunction (int hash_algo_id)
{
@@ -648,60 +644,61 @@ static unsigned __stdcall PeriodicFastPollThreadProc (void *dummy)
}
}
/* Type definitions for function pointers to call NetAPI32 functions */
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);
NETSTATISTICSGET pNetStatisticsGet = NULL;
NETAPIBUFFERSIZE pNetApiBufferSize = NULL;
NETAPIBUFFERFREE pNetApiBufferFree = NULL;
/* 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;
/* Find out whether this is an NT server or workstation if necessary */
if (isWorkstation == -1)
{
HKEY hKey;
if (RegOpenKeyEx (HKEY_LOCAL_MACHINE,
L"SYSTEM\\CurrentControlSet\\Control\\ProductOptions",
0, KEY_READ, &hKey) == ERROR_SUCCESS)
{
wchar_t szValue[32];
dwSize = sizeof (szValue);
isWorkstation = TRUE;
status = RegQueryValueEx (hKey, L"ProductType", 0, NULL,
(LPBYTE) szValue, &dwSize);
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;
RegCloseKey (hKey);
}
}
/* Initialize the NetAPI32 function pointers if necessary */
if (hNetAPI32 == NULL)
{
@@ -756,115 +753,114 @@ BOOL SlowPoll (void)
RandaddBuf ((unsigned char *) lpBuffer, dwSize);
pNetApiBufferFree (lpBuffer);
}
/* 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;
/* 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);
}
- // CryptoAPI: We always have a valid CryptoAPI context when we arrive here but
- // we keep the check for clarity purpose
- if ( !CryptoAPIAvailable )
- return FALSE;
- if (CryptGenRandom (hCryptProv, sizeof (buffer), buffer))
+
+ bStatus = BCryptGenRandom(NULL, buffer, sizeof(buffer), BCRYPT_USE_SYSTEM_PREFERRED_RNG);
+ if (NT_SUCCESS(bStatus))
{
RandaddBuf (buffer, sizeof (buffer));
}
else
{
- /* return error in case CryptGenRandom fails */
- CryptoAPILastError = GetLastError ();
+ /* 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);
}
}
// 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));
}
burn(buffer, sizeof (buffer));
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 */
RandaddIntPtr (GetActiveWindow ()); /* Handle of active window */
RandaddIntPtr (GetCapture ()); /* Handle of window with mouse
capture */
RandaddIntPtr (GetClipboardOwner ()); /* Handle of clipboard owner */
RandaddIntPtr (GetClipboardViewer ()); /* Handle of start of
clpbd.viewer list */
RandaddIntPtr (GetCurrentProcess ()); /* Pseudohandle of current
process */
RandaddInt32 (GetCurrentProcessId ()); /* Current process ID */
RandaddIntPtr (GetCurrentThread ()); /* Pseudohandle of current
thread */
RandaddInt32 (GetCurrentThreadId ()); /* Current thread ID */
RandaddInt32 (GetCurrentTime ()); /* Milliseconds since Windows
started */
RandaddIntPtr (GetDesktopWindow ()); /* Handle of desktop window */
RandaddIntPtr (GetFocus ()); /* Handle of window with kb.focus */
RandaddInt32 (GetInputState ()); /* Whether sys.queue has any events */
RandaddInt32 (GetMessagePos ()); /* Cursor pos.for last message */
RandaddInt32 (GetMessageTime ()); /* 1 ms time for last message */
RandaddIntPtr (GetOpenClipboardWindow ()); /* Handle of window with
clpbd.open */
RandaddIntPtr (GetProcessHeap ()); /* Handle of process heap */
RandaddIntPtr (GetProcessWindowStation ()); /* Handle of procs
window station */
RandaddInt32 (GetQueueStatus (QS_ALLEVENTS)); /* Types of events in
input queue */
/* Get multiword system information */
@@ -901,70 +897,68 @@ BOOL FastPoll (void)
&maximumWorkingSetSize);
RandaddIntPtr (minimumWorkingSetSize);
RandaddIntPtr (maximumWorkingSetSize);
/* The following are fixed for the lifetime of the process so we only
add them once */
if (addedFixedItems == 0)
{
STARTUPINFO startupInfo;
/* Get name of desktop, console window title, new window
position and size, window flags, and handles for stdin,
stdout, and stderr */
startupInfo.cb = sizeof (STARTUPINFO);
GetStartupInfo (&startupInfo);
RandaddBuf ((unsigned char *) &startupInfo, sizeof (STARTUPINFO));
addedFixedItems = TRUE;
}
/* The docs say QPC can fail if appropriate hardware is not
available. It works on 486 & Pentium boxes, but hasn't been tested
for 386 or RISC boxes */
if (QueryPerformanceCounter (&performanceCount))
RandaddBuf ((unsigned char *) &performanceCount, sizeof (LARGE_INTEGER));
else
{
/* Millisecond accuracy at best... */
DWORD dwTicks = GetTickCount ();
RandaddBuf ((unsigned char *) &dwTicks, sizeof (dwTicks));
}
- // CryptoAPI: We always have a valid CryptoAPI context when we arrive here but
- // we keep the check for clarity purpose
- if ( !CryptoAPIAvailable )
- return FALSE;
- if (CryptGenRandom (hCryptProv, sizeof (buffer), buffer))
+
+ bStatus = BCryptGenRandom(NULL, buffer, sizeof(buffer), BCRYPT_USE_SYSTEM_PREFERRED_RNG);
+ if (NT_SUCCESS(bStatus))
{
RandaddBuf (buffer, sizeof (buffer));
}
else
{
- /* return error in case CryptGenRandom fails */
- CryptoAPILastError = GetLastError ();
+ /* return error in case BCryptGenRandom fails */
+ CryptoAPILastError = pRtlNtStatusToDosError (bStatus);
return FALSE;
}
// use RDSEED or RDRAND from CPU as source of entropy if enabled
if ( IsCpuRngEnabled() &&
( (HasRDSEED() && RDSEED_getBytes (buffer, sizeof (buffer)))
|| (HasRDRAND() && RDRAND_getBytes (buffer, sizeof (buffer)))
))
{
RandaddBuf (buffer, sizeof (buffer));
}
burn (buffer, sizeof(buffer));
/* Apply the pool mixing function */
Randmix();
/* Restore the original pool cursor position. If this wasn't done, mouse coordinates
could be written to a limited area of the pool, especially when moving the mouse
uninterruptedly. The severity of the problem would depend on the length of data
written by FastPoll (if it was equal to the size of the pool, mouse coordinates
would be written only to a particular 4-byte area, whenever moving the mouse
uninterruptedly). */
nRandIndex = nOriginalRandIndex;
return TRUE;
}