mirror of
https://github.com/veracrypt/VeraCrypt.git
synced 2025-11-12 03:18:26 -06:00
Windows: Implement RAM encryption for keys on 64-bit machines using ChaCha12 cipher and t1ha non-cryptographic fast hash (https://github.com/leo-yuriev/t1ha)
This commit is contained in:
@@ -418,5 +418,6 @@ typedef struct
|
||||
#define VC_DRIVER_CONFIG_ALLOW_WINDOWS_DEFRAG 0x200
|
||||
#define VC_DRIVER_CONFIG_CLEAR_KEYS_ON_NEW_DEVICE_INSERTION 0x400
|
||||
#define VC_DRIVER_CONFIG_ENABLE_CPU_RNG 0x800
|
||||
#define VC_DRIVER_CONFIG_ENABLE_RAM_ENCRYPTION 0x1000
|
||||
|
||||
#endif /* _WIN32 */
|
||||
|
||||
@@ -1220,6 +1220,7 @@ BOOL IsHwEncryptionEnabled ()
|
||||
#ifndef TC_WINDOWS_BOOT
|
||||
|
||||
static BOOL CpuRngDisabled = TRUE;
|
||||
static BOOL RamEncryptionEnabled = FALSE;
|
||||
|
||||
BOOL IsCpuRngSupported ()
|
||||
{
|
||||
@@ -1239,6 +1240,214 @@ BOOL IsCpuRngEnabled ()
|
||||
return !CpuRngDisabled;
|
||||
}
|
||||
|
||||
BOOL IsRamEncryptionSupported ()
|
||||
{
|
||||
#ifdef _WIN64
|
||||
return TRUE;
|
||||
#else
|
||||
return FALSE;
|
||||
#endif
|
||||
}
|
||||
|
||||
void EnableRamEncryption (BOOL enable)
|
||||
{
|
||||
RamEncryptionEnabled = enable;
|
||||
}
|
||||
|
||||
BOOL IsRamEncryptionEnabled ()
|
||||
{
|
||||
return RamEncryptionEnabled;
|
||||
}
|
||||
|
||||
/* masking for random index to remove bias */
|
||||
byte GetRngMask (byte count)
|
||||
{
|
||||
if (count >= 128)
|
||||
return 0xFF;
|
||||
if (count >= 64)
|
||||
return 0x7F;
|
||||
if (count >= 32)
|
||||
return 0x3F;
|
||||
if (count >= 16)
|
||||
return 0x1F;
|
||||
if (count >= 8)
|
||||
return 0x0F;
|
||||
if (count >= 4)
|
||||
return 0x07;
|
||||
if (count >= 2)
|
||||
return 0x03;
|
||||
return 1;
|
||||
}
|
||||
|
||||
byte GetRandomIndex (ChaCha20RngCtx* pCtx, byte elementsCount)
|
||||
{
|
||||
byte index = 0;
|
||||
byte mask = GetRngMask (elementsCount);
|
||||
|
||||
while (TRUE)
|
||||
{
|
||||
ChaCha20RngGetBytes (pCtx, &index, 1);
|
||||
index &= mask;
|
||||
if (index < elementsCount)
|
||||
break;
|
||||
}
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
#if defined(_WIN64) && !defined (_UEFI) && defined(TC_WINDOWS_DRIVER)
|
||||
/* declaration of variables and functions used for RAM encryption on 64-bit build */
|
||||
static byte* pbKeyDerivationArea = NULL;
|
||||
static ULONG cbKeyDerivationArea = 0;
|
||||
|
||||
static uint64 HashSeedMask = 0;
|
||||
static uint64 CipherIVMask = 0;
|
||||
#ifdef TC_WINDOWS_DRIVER
|
||||
ULONG AllocTag = 'MMCV';
|
||||
#endif
|
||||
|
||||
BOOL InitializeSecurityParameters(GetRandSeedFn rngCallback)
|
||||
{
|
||||
ChaCha20RngCtx ctx;
|
||||
byte pbSeed[CHACHA20RNG_KEYSZ + CHACHA20RNG_IVSZ];
|
||||
#ifdef TC_WINDOWS_DRIVER
|
||||
byte i, tagLength;
|
||||
#endif
|
||||
|
||||
rngCallback (pbSeed, sizeof (pbSeed));
|
||||
|
||||
ChaCha20RngInit (&ctx, pbSeed, rngCallback, 0);
|
||||
|
||||
#ifdef TC_WINDOWS_DRIVER
|
||||
/* generate random tag length between 1 and 4 */
|
||||
tagLength = GetRandomIndex (&ctx, 4) + 1;
|
||||
|
||||
/* generate random value for tag:
|
||||
* Each ASCII character in the tag must be a value in the range 0x20 (space) to 0x7E (tilde)
|
||||
* So we have 95 possibility
|
||||
*/
|
||||
AllocTag = 0;
|
||||
for (i = 0; i < tagLength; i++)
|
||||
{
|
||||
AllocTag = (AllocTag << 8) + (((ULONG) GetRandomIndex (&ctx, 95)) + 0x20);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
cbKeyDerivationArea = 1024 * 1024;
|
||||
pbKeyDerivationArea = (byte*) TCalloc(cbKeyDerivationArea);
|
||||
if (!pbKeyDerivationArea)
|
||||
{
|
||||
cbKeyDerivationArea = 2 * PAGE_SIZE;
|
||||
pbKeyDerivationArea = (byte*) TCalloc(cbKeyDerivationArea);
|
||||
}
|
||||
|
||||
if (!pbKeyDerivationArea)
|
||||
{
|
||||
cbKeyDerivationArea = 0;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* fill key derivation area with random bytes */
|
||||
ChaCha20RngGetBytes (&ctx, pbKeyDerivationArea, cbKeyDerivationArea);
|
||||
|
||||
/* generate hash seed mask */
|
||||
ChaCha20RngGetBytes(&ctx, (unsigned char*) &HashSeedMask, sizeof (HashSeedMask));
|
||||
|
||||
/* generate IV mask */
|
||||
ChaCha20RngGetBytes(&ctx, (unsigned char*) &CipherIVMask, sizeof (CipherIVMask));
|
||||
|
||||
FAST_ERASE64 (pbSeed, sizeof (pbSeed));
|
||||
burn (&ctx, sizeof (ctx));
|
||||
burn (&tagLength, 1);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void ClearSecurityParameters()
|
||||
{
|
||||
if (pbKeyDerivationArea)
|
||||
{
|
||||
FAST_ERASE64 (pbKeyDerivationArea, cbKeyDerivationArea);
|
||||
TCfree (pbKeyDerivationArea);
|
||||
pbKeyDerivationArea =NULL;
|
||||
cbKeyDerivationArea = 0;
|
||||
}
|
||||
|
||||
FAST_ERASE64 (&HashSeedMask, 8);
|
||||
FAST_ERASE64 (&CipherIVMask, 8);
|
||||
#ifdef TC_WINDOWS_DRIVER
|
||||
burn (&AllocTag, sizeof (AllocTag));
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef TC_WINDOWS_DRIVER
|
||||
static void VcProtectMemory (uint64 encID, unsigned char* pbData, size_t cbData, unsigned char* pbData2, size_t cbData2)
|
||||
#else
|
||||
static 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
|
||||
{
|
||||
if (pbKeyDerivationArea)
|
||||
{
|
||||
uint64 hashLow, hashHigh, hashSeed, cipherIV;
|
||||
uint64 pbKey[4];
|
||||
ChaCha256Ctx ctx;
|
||||
|
||||
hashSeed = (((uint64) pbKeyDerivationArea) + encID) ^ HashSeedMask;
|
||||
hashLow = t1ha2_atonce128(&hashHigh, pbKeyDerivationArea, cbKeyDerivationArea, hashSeed);
|
||||
|
||||
/* set the key to the hash result */
|
||||
pbKey[0] = pbKey[2] = hashLow;
|
||||
pbKey[1] = pbKey[3] = hashHigh;
|
||||
|
||||
/* Initialize ChaCha12 cipher */
|
||||
cipherIV = encID ^ CipherIVMask;
|
||||
ChaCha256Init (&ctx, (unsigned char*) pbKey, (unsigned char*) &cipherIV, 12);
|
||||
|
||||
ChaCha256Encrypt (&ctx, pbData, cbData, pbData);
|
||||
ChaCha256Encrypt (&ctx, pbData2, cbData2, pbData2);
|
||||
#ifndef TC_WINDOWS_DRIVER
|
||||
ChaCha256Encrypt (&ctx, pbData3, cbData3, pbData3);
|
||||
ChaCha256Encrypt (&ctx, pbData4, cbData4, pbData4);
|
||||
#endif
|
||||
FAST_ERASE64 (pbKey, sizeof(pbKey));
|
||||
FAST_ERASE64 (&hashLow, 8);
|
||||
FAST_ERASE64 (&hashHigh, 8);
|
||||
FAST_ERASE64 (&hashSeed, 8);
|
||||
FAST_ERASE64 (&cipherIV, 8);
|
||||
burn (&ctx, sizeof (ctx));
|
||||
}
|
||||
}
|
||||
|
||||
uint64 VcGetEncryptionID (PCRYPTO_INFO pCryptoInfo)
|
||||
{
|
||||
return ((uint64) pCryptoInfo->ks) + ((uint64) pCryptoInfo->ks2)
|
||||
#ifndef TC_WINDOWS_DRIVER
|
||||
+ ((uint64) pCryptoInfo->master_keydata) + ((uint64) pCryptoInfo->k2)
|
||||
#endif
|
||||
;
|
||||
}
|
||||
|
||||
void VcProtectKeys (PCRYPTO_INFO pCryptoInfo, uint64 encID)
|
||||
{
|
||||
#ifdef TC_WINDOWS_DRIVER
|
||||
VcProtectMemory (encID, pCryptoInfo->ks, MAX_EXPANDED_KEY, pCryptoInfo->ks2, MAX_EXPANDED_KEY);
|
||||
#else
|
||||
VcProtectMemory (encID, pCryptoInfo->ks, MAX_EXPANDED_KEY,
|
||||
pCryptoInfo->ks2, MAX_EXPANDED_KEY,
|
||||
pCryptoInfo->master_keydata, MASTER_KEYDATA_SIZE,
|
||||
pCryptoInfo->k2, MASTER_KEYDATA_SIZE);
|
||||
#endif
|
||||
}
|
||||
|
||||
void VcUnprotectKeys (PCRYPTO_INFO pCryptoInfo, uint64 encID)
|
||||
{
|
||||
VcProtectKeys (pCryptoInfo, encID);
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -208,6 +208,10 @@ typedef struct
|
||||
# include "GostCipher.h"
|
||||
# include "kuznyechik.h"
|
||||
# include "Camellia.h"
|
||||
# include "chachaRng.h"
|
||||
# ifdef _WIN64
|
||||
# include "t1ha.h"
|
||||
# endif
|
||||
#else
|
||||
# include "CamelliaSmall.h"
|
||||
#endif
|
||||
@@ -381,6 +385,19 @@ 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)
|
||||
BOOL InitializeSecurityParameters(GetRandSeedFn rngCallback);
|
||||
void ClearSecurityParameters();
|
||||
uint64 VcGetEncryptionID (PCRYPTO_INFO pCryptoInfo);
|
||||
void VcProtectKeys (PCRYPTO_INFO pCryptoInfo, uint64 encID);
|
||||
void VcUnprotectKeys (PCRYPTO_INFO pCryptoInfo, uint64 encID);
|
||||
void EncryptDataUnitsCurrentThreadEx (unsigned __int8 *buf, const UINT64_STRUCT *structUnitNo, TC_LARGEST_COMPILER_UINT nbrUnits, PCRYPTO_INFO ci);
|
||||
void DecryptDataUnitsCurrentThreadEx (unsigned __int8 *buf, const UINT64_STRUCT *structUnitNo, TC_LARGEST_COMPILER_UINT nbrUnits, PCRYPTO_INFO ci);
|
||||
#else
|
||||
#define EncryptDataUnitsCurrentThreadEx EncryptDataUnitsCurrentThread
|
||||
#define DecryptDataUnitsCurrentThreadEx DecryptDataUnitsCurrentThread
|
||||
#endif
|
||||
|
||||
BOOL IsAesHwCpuSupported ();
|
||||
void EnableHwEncryption (BOOL enable);
|
||||
BOOL IsHwEncryptionEnabled ();
|
||||
@@ -389,6 +406,10 @@ BOOL IsCpuRngSupported ();
|
||||
void EnableCpuRng (BOOL enable);
|
||||
BOOL IsCpuRngEnabled ();
|
||||
|
||||
BOOL IsRamEncryptionSupported ();
|
||||
void EnableRamEncryption (BOOL enable);
|
||||
BOOL IsRamEncryptionEnabled ();
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -111,6 +111,43 @@ static TC_MUTEX DequeueMutex;
|
||||
static TC_EVENT WorkItemReadyEvent;
|
||||
static TC_EVENT WorkItemCompletedEvent;
|
||||
|
||||
#if defined(_WIN64) && defined(TC_WINDOWS_DRIVER)
|
||||
void EncryptDataUnitsCurrentThreadEx (unsigned __int8 *buf, const UINT64_STRUCT *structUnitNo, TC_LARGEST_COMPILER_UINT nbrUnits, PCRYPTO_INFO ci)
|
||||
{
|
||||
if (IsRamEncryptionEnabled())
|
||||
{
|
||||
CRYPTO_INFO tmpCI;
|
||||
memcpy (&tmpCI, ci, sizeof (CRYPTO_INFO));
|
||||
VcUnprotectKeys (&tmpCI, VcGetEncryptionID (ci));
|
||||
|
||||
EncryptDataUnitsCurrentThread (buf, structUnitNo, nbrUnits, &tmpCI);
|
||||
|
||||
burn (&tmpCI, sizeof(CRYPTO_INFO));
|
||||
}
|
||||
else
|
||||
EncryptDataUnitsCurrentThread (buf, structUnitNo, nbrUnits, ci);
|
||||
}
|
||||
|
||||
void DecryptDataUnitsCurrentThreadEx (unsigned __int8 *buf, const UINT64_STRUCT *structUnitNo, TC_LARGEST_COMPILER_UINT nbrUnits, PCRYPTO_INFO ci)
|
||||
{
|
||||
if (IsRamEncryptionEnabled())
|
||||
{
|
||||
CRYPTO_INFO tmpCI;
|
||||
memcpy (&tmpCI, ci, sizeof (CRYPTO_INFO));
|
||||
VcUnprotectKeys (&tmpCI, VcGetEncryptionID (ci));
|
||||
|
||||
DecryptDataUnitsCurrentThread (buf, structUnitNo, nbrUnits, &tmpCI);
|
||||
|
||||
burn (&tmpCI, sizeof(CRYPTO_INFO));
|
||||
}
|
||||
else
|
||||
DecryptDataUnitsCurrentThread (buf, structUnitNo, nbrUnits, ci);
|
||||
}
|
||||
|
||||
#else
|
||||
#define EncryptDataUnitsCurrentThreadEx EncryptDataUnitsCurrentThread
|
||||
#define DecryptDataUnitsCurrentThreadEx DecryptDataUnitsCurrentThread
|
||||
#endif
|
||||
|
||||
static WorkItemState GetWorkItemState (EncryptionThreadPoolWorkItem *workItem)
|
||||
{
|
||||
@@ -152,11 +189,11 @@ static TC_THREAD_PROC EncryptionThreadProc (void *threadArg)
|
||||
switch (workItem->Type)
|
||||
{
|
||||
case DecryptDataUnitsWork:
|
||||
DecryptDataUnitsCurrentThread (workItem->Encryption.Data, &workItem->Encryption.StartUnitNo, workItem->Encryption.UnitCount, workItem->Encryption.CryptoInfo);
|
||||
DecryptDataUnitsCurrentThreadEx (workItem->Encryption.Data, &workItem->Encryption.StartUnitNo, workItem->Encryption.UnitCount, workItem->Encryption.CryptoInfo);
|
||||
break;
|
||||
|
||||
case EncryptDataUnitsWork:
|
||||
EncryptDataUnitsCurrentThread (workItem->Encryption.Data, &workItem->Encryption.StartUnitNo, workItem->Encryption.UnitCount, workItem->Encryption.CryptoInfo);
|
||||
EncryptDataUnitsCurrentThreadEx (workItem->Encryption.Data, &workItem->Encryption.StartUnitNo, workItem->Encryption.UnitCount, workItem->Encryption.CryptoInfo);
|
||||
break;
|
||||
|
||||
case DeriveKeyWork:
|
||||
@@ -414,11 +451,11 @@ void EncryptionThreadPoolDoWork (EncryptionThreadPoolWorkType type, byte *data,
|
||||
switch (type)
|
||||
{
|
||||
case DecryptDataUnitsWork:
|
||||
DecryptDataUnitsCurrentThread (data, startUnitNo, unitCount, cryptoInfo);
|
||||
DecryptDataUnitsCurrentThreadEx (data, startUnitNo, unitCount, cryptoInfo);
|
||||
break;
|
||||
|
||||
case EncryptDataUnitsWork:
|
||||
EncryptDataUnitsCurrentThread (data, startUnitNo, unitCount, cryptoInfo);
|
||||
EncryptDataUnitsCurrentThreadEx (data, startUnitNo, unitCount, cryptoInfo);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
@@ -248,9 +248,14 @@ void ThrowFatalException(int line);
|
||||
/* variables used in the implementation of enhanced protection of NX pool under Windows 8 and later */
|
||||
extern POOL_TYPE ExDefaultNonPagedPoolType;
|
||||
extern ULONG ExDefaultMdlProtection;
|
||||
#ifdef _WIN64
|
||||
extern ULONG AllocTag;
|
||||
#else
|
||||
#define AllocTag 'MMCV'
|
||||
#endif
|
||||
|
||||
#define TCalloc(size) ((void *) ExAllocatePoolWithTag( ExDefaultNonPagedPoolType, size, 'MMCV' ))
|
||||
#define TCfree(memblock) ExFreePoolWithTag( memblock, 'MMCV' )
|
||||
#define TCalloc(size) ((void *) ExAllocatePoolWithTag( ExDefaultNonPagedPoolType, size, AllocTag ))
|
||||
#define TCfree(memblock) ExFreePoolWithTag( memblock, AllocTag )
|
||||
|
||||
#define DEVICE_DRIVER
|
||||
|
||||
|
||||
Reference in New Issue
Block a user