Windows: enhancement to RAM encryption

- use a more standard-looking memory value tag instead of fully random one that will look suspicious and outstanding
 - If we fail to allocate 1MiB for derivation area, we device the size by two in a loop until we succeed. This is better than falling back directly to 8KiB size
 - Better method to derive actual encryption key: instead of simply duplicating 128bit key value, we combine a xor addition and self-encryption to build a 256-bit key
 - use both encID and pbKeyDerivationArea to derive IV for encryption and not only endID
This commit is contained in:
Mounir IDRASSI 2023-09-29 22:26:54 +02:00
parent 5192eac233
commit c0f8179f2a
No known key found for this signature in database
GPG Key ID: FC1B00364B3FE937
1 changed files with 55 additions and 17 deletions

View File

@ -1305,8 +1305,8 @@ BOOL InitializeSecurityParameters(GetRandSeedFn rngCallback)
ChaCha20RngCtx ctx;
byte pbSeed[CHACHA20RNG_KEYSZ + CHACHA20RNG_IVSZ];
#ifdef TC_WINDOWS_DRIVER
byte i, tagLength;
byte i;
char randomStr[4];
Dump ("InitializeSecurityParameters BEGIN\n");
#endif
@ -1315,28 +1315,57 @@ BOOL InitializeSecurityParameters(GetRandSeedFn rngCallback)
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
/* Generate random value for tag that is similar to pool tag values used by Windows kernel.
* Fully random tag would be too suspicious and outstanding.
* First character is always a capital letter.
* Second character is a letter, lowercase or uppercase.
* Third character is a letter, lowercase or uppercase.
* Fourth character is a letter or a digit.
*/
/* 1. First character (Capital Letter) */
randomStr[0] = 'A' + GetRandomIndex(&ctx, 26);
/* 2. Second character (Letter) */
i = GetRandomIndex(&ctx, 52);
if (i < 26)
randomStr[1] = 'A' + i;
else
randomStr[1] = 'a' + (i - 26);
/* 3. Third character (Letter) */
i = GetRandomIndex(&ctx, 52);
if (i < 26)
randomStr[2] = 'A' + i;
else
randomStr[2] = 'a' + (i - 26);
/* 4. Fourth character (Letter or Digit) */
i = GetRandomIndex(&ctx, 62);
if (i < 26)
randomStr[3] = 'A' + i;
else if (i < 52)
randomStr[3] = 'a' + (i - 26);
else
randomStr[3] = '0' + (i - 52);
/* combine all characters in reverse order as explained in MSDN */
AllocTag = 0;
for (i = 0; i < tagLength; i++)
for (i = 0; i < 4; i++)
{
AllocTag = (AllocTag << 8) + (((ULONG) GetRandomIndex (&ctx, 95)) + 0x20);
AllocTag = (AllocTag << 8) + randomStr[3-i];
}
#endif
cbKeyDerivationArea = 1024 * 1024;
pbKeyDerivationArea = (byte*) TCalloc(cbKeyDerivationArea);
if (!pbKeyDerivationArea)
do
{
cbKeyDerivationArea = 2 * PAGE_SIZE;
pbKeyDerivationArea = (byte*) TCalloc(cbKeyDerivationArea);
}
if (!pbKeyDerivationArea)
cbKeyDerivationArea >>= 1;
} while (!pbKeyDerivationArea && (cbKeyDerivationArea >= (2*PAGE_SIZE)));
if (!pbKeyDerivationArea)
{
@ -1357,7 +1386,7 @@ BOOL InitializeSecurityParameters(GetRandSeedFn rngCallback)
FAST_ERASE64 (pbSeed, sizeof (pbSeed));
burn (&ctx, sizeof (ctx));
#ifdef TC_WINDOWS_DRIVER
burn (&tagLength, 1);
burn (randomStr, sizeof(randomStr));
Dump ("InitializeSecurityParameters return=TRUE END\n");
#endif
@ -1402,11 +1431,20 @@ void VcProtectMemory (uint64 encID, unsigned char* pbData, size_t cbData,
hashLow = t1ha2_atonce128(&hashHigh, pbKeyDerivationArea, cbKeyDerivationArea, hashSeed);
/* set the key to the hash result */
pbKey[0] = pbKey[2] = hashLow;
pbKey[1] = pbKey[3] = hashHigh;
pbKey[0] = hashLow;
pbKey[1] = hashHigh;
/* we now have a 128-bit key and we will expand it to 256-bit by using ChaCha12 cipher */
/* first we need to generate a the other 128-bit half of the key */
pbKey[2] = hashLow ^ hashHigh;
pbKey[3] = hashLow + hashHigh;
/* Initialize ChaCha12 cipher */
cipherIV = encID ^ CipherIVMask;
ChaCha256Init (&ctx, (unsigned char*) pbKey, (unsigned char*) &hashSeed, 12);
/* encrypt the key by itself */
ChaCha256Encrypt (&ctx, (unsigned char*) pbKey, sizeof(pbKey), (unsigned char*) pbKey);
/* Initialize ChaCha12 cipher */
cipherIV = (((uint64) pbKeyDerivationArea) + encID) ^ CipherIVMask;
ChaCha256Init (&ctx, (unsigned char*) pbKey, (unsigned char*) &cipherIV, 12);
ChaCha256Encrypt (&ctx, pbData, cbData, pbData);