From 321715202aed04dd9892d1c0686d080763ab212d Mon Sep 17 00:00:00 2001 From: Mounir IDRASSI Date: Sat, 2 Mar 2019 10:14:21 +0100 Subject: [PATCH] Windows: Generalize RAM encryption for keys to VeraCrypt binaries, especially Format and Expander --- src/Common/Crypto.c | 10 +++- src/Common/Crypto.h | 9 +++- src/Common/Dlgcode.c | 82 +++++++++++++++++++++++++++++++ src/Common/Dlgcode.h | 3 ++ src/Common/EncryptionThreadPool.c | 2 +- src/Common/Format.c | 7 +++ src/Common/Tcdefs.h | 3 ++ src/Common/Tests.c | 5 ++ src/Crypto/Crypto.vcxproj | 6 +++ src/Crypto/Crypto.vcxproj.filters | 18 +++++++ src/ExpandVolume/ExpandVolume.c | 7 +++ src/Format/InPlace.c | 41 +++++++++++++++- 12 files changed, 187 insertions(+), 6 deletions(-) diff --git a/src/Common/Crypto.c b/src/Common/Crypto.c index 6a918953..501cd165 100644 --- a/src/Common/Crypto.c +++ b/src/Common/Crypto.c @@ -1295,7 +1295,7 @@ byte GetRandomIndex (ChaCha20RngCtx* pCtx, byte elementsCount) return index; } -#if defined(_WIN64) && !defined (_UEFI) && defined(TC_WINDOWS_DRIVER) +#if defined(_WIN64) && !defined (_UEFI) /* declaration of variables and functions used for RAM encryption on 64-bit build */ static byte* pbKeyDerivationArea = NULL; static ULONG cbKeyDerivationArea = 0; @@ -1306,15 +1306,19 @@ static uint64 CipherIVMask = 0; ULONG AllocTag = 'MMCV'; #endif +#if !defined(PAGE_SIZE) +#define PAGE_SIZE 4096 +#endif + BOOL InitializeSecurityParameters(GetRandSeedFn rngCallback) { ChaCha20RngCtx ctx; byte pbSeed[CHACHA20RNG_KEYSZ + CHACHA20RNG_IVSZ]; #ifdef TC_WINDOWS_DRIVER byte i, tagLength; -#endif Dump ("InitializeSecurityParameters BEGIN\n"); +#endif rngCallback (pbSeed, sizeof (pbSeed)); @@ -1362,9 +1366,11 @@ BOOL InitializeSecurityParameters(GetRandSeedFn rngCallback) FAST_ERASE64 (pbSeed, sizeof (pbSeed)); burn (&ctx, sizeof (ctx)); +#ifdef TC_WINDOWS_DRIVER burn (&tagLength, 1); Dump ("InitializeSecurityParameters return=TRUE END\n"); +#endif return TRUE; } diff --git a/src/Common/Crypto.h b/src/Common/Crypto.h index 5a8724f6..600fee92 100644 --- a/src/Common/Crypto.h +++ b/src/Common/Crypto.h @@ -385,10 +385,17 @@ void DecryptDataUnitsCurrentThread (unsigned __int8 *buf, const UINT64_STRUCT *s void EncryptBuffer (unsigned __int8 *buf, TC_LARGEST_COMPILER_UINT len, PCRYPTO_INFO cryptoInfo); void DecryptBuffer (unsigned __int8 *buf, TC_LARGEST_COMPILER_UINT len, PCRYPTO_INFO cryptoInfo); -#if defined(_WIN64) && !defined (_UEFI) && defined(TC_WINDOWS_DRIVER) +#if defined(_WIN64) && !defined (_UEFI) BOOL InitializeSecurityParameters(GetRandSeedFn rngCallback); void ClearSecurityParameters(); +#ifdef TC_WINDOWS_DRIVER void VcProtectMemory (uint64 encID, unsigned char* pbData, size_t cbData, unsigned char* pbData2, size_t cbData2); +#else +void VcProtectMemory (uint64 encID, unsigned char* pbData, size_t cbData, + unsigned char* pbData2, size_t cbData2, + unsigned char* pbData3, size_t cbData3, + unsigned char* pbData4, size_t cbData4); +#endif uint64 VcGetEncryptionID (PCRYPTO_INFO pCryptoInfo); void VcProtectKeys (PCRYPTO_INFO pCryptoInfo, uint64 encID); void VcUnprotectKeys (PCRYPTO_INFO pCryptoInfo, uint64 encID); diff --git a/src/Common/Dlgcode.c b/src/Common/Dlgcode.c index 3d8ee6fc..6d6ed69b 100644 --- a/src/Common/Dlgcode.c +++ b/src/Common/Dlgcode.c @@ -60,6 +60,8 @@ #include "Boot/Windows/BootCommon.h" #include "Progress.h" #include "zip.h" +#include "rdrand.h" +#include "jitterentropy.h" #ifdef TCMOUNT #include "Mount/Mount.h" @@ -3203,6 +3205,17 @@ void InitApp (HINSTANCE hInstance, wchar_t *lpszCommandLine) InitHelpFileName (); #ifndef SETUP +#ifdef _WIN64 + if (IsOSAtLeast (WIN_7)) + { + EnableRamEncryption ((ReadDriverConfigurationFlags() & VC_DRIVER_CONFIG_ENABLE_RAM_ENCRYPTION) ? TRUE : FALSE); + if (IsRamEncryptionEnabled()) + { + if (!InitializeSecurityParameters(GetAppRandomSeed)) + AbortProcess("OUTOFMEMORY"); + } + } +#endif if (!EncryptionThreadPoolStart (ReadEncryptionThreadPoolFreeCpuCountLimit())) { handleWin32Error (NULL, SRC_POS); @@ -13894,3 +13907,72 @@ BOOL BufferHasPattern (const unsigned char* buffer, size_t bufferLen, const void return bRet; } + +#if !defined(SETUP) && defined(_WIN64) + +#define RtlGenRandom SystemFunction036 +extern "C" BOOLEAN NTAPI RtlGenRandom(PVOID RandomBuffer, ULONG RandomBufferLength); + +void GetAppRandomSeed (unsigned char* pbRandSeed, size_t cbRandSeed) +{ + LARGE_INTEGER iSeed; + SYSTEMTIME sysTime; + byte digest[WHIRLPOOL_DIGESTSIZE]; + WHIRLPOOL_CTX tctx; + size_t count; + + while (cbRandSeed) + { + WHIRLPOOL_init (&tctx); + // we hash current content of digest buffer which is uninitialized the first time + WHIRLPOOL_add (digest, WHIRLPOOL_DIGESTSIZE, &tctx); + + // we use various time information as source of entropy + GetSystemTime (&sysTime); + WHIRLPOOL_add ((unsigned char *) &sysTime, sizeof(sysTime), &tctx); + if (QueryPerformanceCounter (&iSeed)) + WHIRLPOOL_add ((unsigned char *) &(iSeed.QuadPart), sizeof(iSeed.QuadPart), &tctx); + if (QueryPerformanceFrequency (&iSeed)) + WHIRLPOOL_add ((unsigned char *) &(iSeed.QuadPart), sizeof(iSeed.QuadPart), &tctx); + + /* use Windows random generator as entropy source */ + if (RtlGenRandom (digest, sizeof (digest))) + WHIRLPOOL_add (digest, sizeof(digest), &tctx); + + /* 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*) digest, sizeof (digest)); + if (rndLen > 0) + WHIRLPOOL_add (digest, (unsigned int) rndLen, &tctx); + jent_entropy_collector_free (ec); + } + } + + // use RDSEED or RDRAND from CPU as source of entropy if enabled + if ( IsCpuRngEnabled() && + ( (HasRDSEED() && RDSEED_getBytes (digest, sizeof (digest))) + || (HasRDRAND() && RDRAND_getBytes (digest, sizeof (digest))) + )) + { + WHIRLPOOL_add (digest, sizeof(digest), &tctx); + } + WHIRLPOOL_finalize (&tctx, digest); + + count = VC_MIN (cbRandSeed, sizeof (digest)); + + // copy digest value to seed buffer + memcpy (pbRandSeed, digest, count); + cbRandSeed -= count; + pbRandSeed += count; + } + + FAST_ERASE64 (digest, sizeof (digest)); + FAST_ERASE64 (&iSeed.QuadPart, 8); + burn (&sysTime, sizeof(sysTime)); + burn (&tctx, sizeof(tctx)); +} +#endif diff --git a/src/Common/Dlgcode.h b/src/Common/Dlgcode.h index e97e50cf..8a75f264 100644 --- a/src/Common/Dlgcode.h +++ b/src/Common/Dlgcode.h @@ -537,6 +537,9 @@ BOOL VerifyModuleSignature (const wchar_t* path); void GetInstallationPath (HWND hwndDlg, wchar_t* szInstallPath, DWORD cchSize, BOOL* pbInstallPathDetermined); BOOL GetSetupconfigLocation (wchar_t* path, DWORD cchSize); BOOL BufferHasPattern (const unsigned char* buffer, size_t bufferLen, const void* pattern, size_t patternLen); +#ifdef _WIN64 +void GetAppRandomSeed (unsigned char* pbRandSeed, size_t cbRandSeed); +#endif #ifdef __cplusplus } diff --git a/src/Common/EncryptionThreadPool.c b/src/Common/EncryptionThreadPool.c index fdf1101c..461f2847 100644 --- a/src/Common/EncryptionThreadPool.c +++ b/src/Common/EncryptionThreadPool.c @@ -111,7 +111,7 @@ static TC_MUTEX DequeueMutex; static TC_EVENT WorkItemReadyEvent; static TC_EVENT WorkItemCompletedEvent; -#if defined(_WIN64) && defined(TC_WINDOWS_DRIVER) +#if defined(_WIN64) void EncryptDataUnitsCurrentThreadEx (unsigned __int8 *buf, const UINT64_STRUCT *structUnitNo, TC_LARGEST_COMPILER_UINT nbrUnits, PCRYPTO_INFO ci) { if (IsRamEncryptionEnabled()) diff --git a/src/Common/Format.c b/src/Common/Format.c index b67ac511..bd33f754 100644 --- a/src/Common/Format.c +++ b/src/Common/Format.c @@ -171,6 +171,13 @@ int TCFormatVolume (volatile FORMAT_VOL_PARAMETERS *volParams) return nStatus? nStatus : ERR_OUTOFMEMORY; } +#ifdef _WIN64 + if (IsRamEncryptionEnabled ()) + { + VcProtectKeys (cryptoInfo, VcGetEncryptionID (cryptoInfo)); + } +#endif + begin_format: if (volParams->bDevice) diff --git a/src/Common/Tcdefs.h b/src/Common/Tcdefs.h index ec1df6a4..ed7b330e 100644 --- a/src/Common/Tcdefs.h +++ b/src/Common/Tcdefs.h @@ -343,6 +343,9 @@ extern VOID NTAPI KeRestoreExtendedProcessorState ( # define Dump(...) # define DumpMem(...) # endif +#elif !defined (TC_WINDOWS_BOOT) +# define Dump(...) +# define DumpMem(...) #endif #if !defined (trace_msg) && !defined (TC_WINDOWS_BOOT) diff --git a/src/Common/Tests.c b/src/Common/Tests.c index be0018a8..0af4313e 100644 --- a/src/Common/Tests.c +++ b/src/Common/Tests.c @@ -720,6 +720,11 @@ BOOL TestSectorBufEncryption (PCRYPTO_INFO ci) if (!EAInitMode (ci, key2)) return FALSE; +#ifdef _WIN64 + if (IsRamEncryptionEnabled ()) + VcProtectKeys (ci, VcGetEncryptionID (ci)); +#endif + // Each data unit will contain the same plaintext for (i = 0; i < nbrUnits; i++) { diff --git a/src/Crypto/Crypto.vcxproj b/src/Crypto/Crypto.vcxproj index 9f351bee..027a87e0 100644 --- a/src/Crypto/Crypto.vcxproj +++ b/src/Crypto/Crypto.vcxproj @@ -232,6 +232,9 @@ + + + @@ -258,6 +261,9 @@ + + + diff --git a/src/Crypto/Crypto.vcxproj.filters b/src/Crypto/Crypto.vcxproj.filters index 7a8da57e..e7b3c3a5 100644 --- a/src/Crypto/Crypto.vcxproj.filters +++ b/src/Crypto/Crypto.vcxproj.filters @@ -72,6 +72,15 @@ Source Files + + Source Files + + + Source Files + + + Source Files + @@ -146,6 +155,15 @@ Header Files + + Header Files + + + Header Files + + + Header Files + diff --git a/src/ExpandVolume/ExpandVolume.c b/src/ExpandVolume/ExpandVolume.c index 0a9733a4..5a476ba3 100644 --- a/src/ExpandVolume/ExpandVolume.c +++ b/src/ExpandVolume/ExpandVolume.c @@ -672,6 +672,13 @@ static int ExpandVolume (HWND hwndDlg, wchar_t *lpszVolume, Password *pVolumePas goto error; } +#ifdef _WIN64 + if (IsRamEncryptionEnabled()) + { + VcProtectKeys (cryptoInfo, VcGetEncryptionID (cryptoInfo)); + } +#endif + if (cryptoInfo->HeaderFlags & TC_HEADER_FLAG_ENCRYPTED_SYSTEM) { nStatus = ERR_SYS_HIDVOL_HEAD_REENC_MODE_WRONG; diff --git a/src/Format/InPlace.c b/src/Format/InPlace.c index b2f1b386..7117a8a4 100644 --- a/src/Format/InPlace.c +++ b/src/Format/InPlace.c @@ -869,6 +869,13 @@ int EncryptPartitionInPlaceResume (HANDLE dev, if (nStatus != ERR_SUCCESS) goto closing_seq; +#ifdef _WIN64 + if (IsRamEncryptionEnabled ()) + { + VcProtectKeys (masterCryptoInfo, VcGetEncryptionID (masterCryptoInfo)); + VcProtectKeys (headerCryptoInfo, VcGetEncryptionID (headerCryptoInfo)); + } +#endif remainingBytes = masterCryptoInfo->VolumeSize.Value - masterCryptoInfo->EncryptedAreaLength.Value; @@ -1389,6 +1396,13 @@ int DecryptPartitionInPlace (volatile FORMAT_VOL_PARAMETERS *volParams, volatile if (nStatus != ERR_SUCCESS) goto closing_seq; +#ifdef _WIN64 + if (IsRamEncryptionEnabled ()) + { + VcProtectKeys (masterCryptoInfo, VcGetEncryptionID (masterCryptoInfo)); + VcProtectKeys (headerCryptoInfo, VcGetEncryptionID (headerCryptoInfo)); + } +#endif if (masterCryptoInfo->LegacyVolume) { @@ -1784,6 +1798,7 @@ int FastVolumeHeaderUpdate (HANDLE dev, CRYPTO_INFO *headerCryptoInfo, CRYPTO_IN DWORD dwError; uint32 headerCrc32; byte *fieldPos; + PCRYPTO_INFO pCryptoInfo = headerCryptoInfo; header = (byte *) TCalloc (TC_VOLUME_HEADER_EFFECTIVE_SIZE); @@ -1804,8 +1819,23 @@ int FastVolumeHeaderUpdate (HANDLE dev, CRYPTO_INFO *headerCryptoInfo, CRYPTO_IN goto closing_seq; } +#ifdef _WIN64 + if (IsRamEncryptionEnabled()) + { + pCryptoInfo = crypto_open(); + if (!pCryptoInfo) + { + nStatus = ERR_OUTOFMEMORY; + goto closing_seq; + } - DecryptBuffer (header + HEADER_ENCRYPTED_DATA_OFFSET, HEADER_ENCRYPTED_DATA_SIZE, headerCryptoInfo); + memcpy (pCryptoInfo, headerCryptoInfo, sizeof (CRYPTO_INFO)); + VcUnprotectKeys (pCryptoInfo, VcGetEncryptionID (headerCryptoInfo)); + } +#endif + + + DecryptBuffer (header + HEADER_ENCRYPTED_DATA_OFFSET, HEADER_ENCRYPTED_DATA_SIZE, pCryptoInfo); if (GetHeaderField32 (header, TC_HEADER_OFFSET_MAGIC) != 0x56455241) { @@ -1828,7 +1858,7 @@ int FastVolumeHeaderUpdate (HANDLE dev, CRYPTO_INFO *headerCryptoInfo, CRYPTO_IN fieldPos = (byte *) header + TC_HEADER_OFFSET_HEADER_CRC; mputLong (fieldPos, headerCrc32); - EncryptBuffer (header + HEADER_ENCRYPTED_DATA_OFFSET, HEADER_ENCRYPTED_DATA_SIZE, headerCryptoInfo); + EncryptBuffer (header + HEADER_ENCRYPTED_DATA_OFFSET, HEADER_ENCRYPTED_DATA_SIZE, pCryptoInfo); if (SetFilePointerEx (dev, offset, NULL, FILE_BEGIN) == 0 @@ -1843,6 +1873,13 @@ int FastVolumeHeaderUpdate (HANDLE dev, CRYPTO_INFO *headerCryptoInfo, CRYPTO_IN dwError = GetLastError(); +#ifdef _WIN64 + if (IsRamEncryptionEnabled() && pCryptoInfo) + { + crypto_close(pCryptoInfo); + } +#endif + burn (header, TC_VOLUME_HEADER_EFFECTIVE_SIZE); VirtualUnlock (header, TC_VOLUME_HEADER_EFFECTIVE_SIZE); TCfree (header);