VeraCrypt
aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMounir IDRASSI <mounir.idrassi@idrix.fr>2016-08-08 00:49:00 +0200
committerMounir IDRASSI <mounir.idrassi@idrix.fr>2016-08-15 01:09:05 +0200
commit5b381ce7d7ec45e02765b4a180f9aa1ee8aeee40 (patch)
tree49f9cc8a5cc65386b021566e9b7d7ec631923b79
parent3fb2eedab8ef586cd2686efba0b668a5070fd0af (diff)
downloadVeraCrypt-5b381ce7d7ec45e02765b4a180f9aa1ee8aeee40.tar.gz
VeraCrypt-5b381ce7d7ec45e02765b4a180f9aa1ee8aeee40.zip
Windows: Fix vulnerability inherited from TrueCrypt that allows an attacker to detect with high probability if a hidden volume is present. Vulnerability reported by Ivanov Alexey Mikhailovich.
-rw-r--r--src/Common/Format.c53
-rw-r--r--src/Common/Password.c42
-rw-r--r--src/Common/Volumes.c99
-rw-r--r--src/ExpandVolume/ExpandVolume.c47
-rw-r--r--src/Format/InPlace.c79
5 files changed, 288 insertions, 32 deletions
diff --git a/src/Common/Format.c b/src/Common/Format.c
index f3114e5e..7d6f3edb 100644
--- a/src/Common/Format.c
+++ b/src/Common/Format.c
@@ -566,10 +566,63 @@ begin_format:
// Fill reserved header sectors (including the backup header area) with random data
if (!volParams->hiddenVol)
{
+ BOOL bUpdateBackup = FALSE;
+
nStatus = WriteRandomDataToReservedHeaderAreas (hwndDlg, dev, cryptoInfo, dataAreaSize, FALSE, FALSE);
if (nStatus != ERR_SUCCESS)
goto error;
+
+ // write fake hidden volume header to protect against attacks that use statistical entropy
+ // analysis to detect presence of hidden volumes.
+
+ while (TRUE)
+ {
+ PCRYPTO_INFO dummyInfo = NULL;
+ LARGE_INTEGER hiddenOffset;
+
+ hiddenOffset.QuadPart = bUpdateBackup ? dataAreaSize + TC_VOLUME_HEADER_GROUP_SIZE + TC_HIDDEN_VOLUME_HEADER_OFFSET: TC_HIDDEN_VOLUME_HEADER_OFFSET;
+
+ nStatus = CreateVolumeHeaderInMemory (hwndDlg, FALSE,
+ header,
+ volParams->ea,
+ FIRST_MODE_OF_OPERATION_ID,
+ NULL,
+ 0,
+ 0,
+ NULL,
+ &dummyInfo,
+ dataAreaSize,
+ dataAreaSize,
+ dataOffset,
+ dataAreaSize,
+ 0,
+ volParams->headerFlags,
+ FormatSectorSize,
+ FALSE);
+
+ if (nStatus != ERR_SUCCESS)
+ goto error;
+
+ crypto_close (dummyInfo);
+
+ if (!SetFilePointerEx ((HANDLE) dev, hiddenOffset, NULL, FILE_BEGIN))
+ {
+ nStatus = ERR_OS_ERROR;
+ goto error;
+ }
+
+ if (!WriteEffectiveVolumeHeader (volParams->bDevice, dev, header))
+ {
+ nStatus = ERR_OS_ERROR;
+ goto error;
+ }
+
+ if (bUpdateBackup)
+ break;
+
+ bUpdateBackup = TRUE;
+ }
}
#ifndef DEBUG
diff --git a/src/Common/Password.c b/src/Common/Password.c
index 2c9e77c3..1c9083a3 100644
--- a/src/Common/Password.c
+++ b/src/Common/Password.c
@@ -437,9 +437,51 @@ int ChangePwd (const wchar_t *lpszVolume, Password *oldPassword, int old_pkcs5,
&& (cryptoInfo->HeaderFlags & TC_HEADER_FLAG_NONSYS_INPLACE_ENC) != 0
&& (cryptoInfo->HeaderFlags & ~TC_HEADER_FLAG_NONSYS_INPLACE_ENC) == 0)
{
+ PCRYPTO_INFO dummyInfo = NULL;
+ LARGE_INTEGER hiddenOffset;
+
nStatus = WriteRandomDataToReservedHeaderAreas (hwndDlg, dev, cryptoInfo, cryptoInfo->VolumeSize.Value, !backupHeader, backupHeader);
if (nStatus != ERR_SUCCESS)
goto error;
+
+ // write fake hidden volume header to protect against attacks that use statistical entropy
+ // analysis to detect presence of hidden volumes
+ hiddenOffset.QuadPart = backupHeader ? cryptoInfo->VolumeSize.Value + TC_VOLUME_HEADER_GROUP_SIZE + TC_HIDDEN_VOLUME_HEADER_OFFSET: TC_HIDDEN_VOLUME_HEADER_OFFSET;
+
+ nStatus = CreateVolumeHeaderInMemory (hwndDlg, FALSE,
+ buffer,
+ cryptoInfo->ea,
+ cryptoInfo->mode,
+ NULL,
+ 0,
+ 0,
+ NULL,
+ &dummyInfo,
+ cryptoInfo->VolumeSize.Value,
+ cryptoInfo->VolumeSize.Value,
+ cryptoInfo->EncryptedAreaStart.Value,
+ cryptoInfo->EncryptedAreaLength.Value,
+ truecryptMode? 0 : cryptoInfo->RequiredProgramVersion,
+ cryptoInfo->HeaderFlags,
+ cryptoInfo->SectorSize,
+ wipePass < wipePassCount - 1);
+
+ if (nStatus != ERR_SUCCESS)
+ goto error;
+
+ crypto_close (dummyInfo);
+
+ if (!SetFilePointerEx ((HANDLE) dev, hiddenOffset, NULL, FILE_BEGIN))
+ {
+ nStatus = ERR_OS_ERROR;
+ goto error;
+ }
+
+ if (!WriteEffectiveVolumeHeader (bDevice, dev, buffer))
+ {
+ nStatus = ERR_OS_ERROR;
+ goto error;
+ }
}
FlushFileBuffers (dev);
diff --git a/src/Common/Volumes.c b/src/Common/Volumes.c
index 816d94f0..8ad40ac1 100644
--- a/src/Common/Volumes.c
+++ b/src/Common/Volumes.c
@@ -809,7 +809,7 @@ int CreateVolumeHeaderInMemory (HWND hwndDlg, BOOL bBoot, char *header, int ea,
unsigned char *p = (unsigned char *) header;
static CRYPTOPP_ALIGN_DATA(16) KEY_INFO keyInfo;
- int nUserKeyLen = password->Length;
+ int nUserKeyLen = password? password->Length : 0;
PCRYPTO_INFO cryptoInfo = crypto_open ();
static char dk[MASTER_KEYDATA_SIZE];
int x;
@@ -844,7 +844,10 @@ int CreateVolumeHeaderInMemory (HWND hwndDlg, BOOL bBoot, char *header, int ea,
}
if (!RandgetBytes (hwndDlg, keyInfo.master_keydata, bytesNeeded, TRUE))
+ {
+ crypto_close (cryptoInfo);
return ERR_CIPHER_INIT_WEAK_KEY;
+ }
}
else
{
@@ -853,9 +856,17 @@ int CreateVolumeHeaderInMemory (HWND hwndDlg, BOOL bBoot, char *header, int ea,
}
// User key
- memcpy (keyInfo.userKey, password->Text, nUserKeyLen);
- keyInfo.keyLength = nUserKeyLen;
- keyInfo.noIterations = get_pkcs5_iteration_count (pkcs5_prf, pim, FALSE, bBoot);
+ if (password)
+ {
+ memcpy (keyInfo.userKey, password->Text, nUserKeyLen);
+ keyInfo.keyLength = nUserKeyLen;
+ keyInfo.noIterations = get_pkcs5_iteration_count (pkcs5_prf, pim, FALSE, bBoot);
+ }
+ else
+ {
+ keyInfo.keyLength = 0;
+ keyInfo.noIterations = 0;
+ }
// User selected encryption algorithm
cryptoInfo->ea = ea;
@@ -871,34 +882,51 @@ int CreateVolumeHeaderInMemory (HWND hwndDlg, BOOL bBoot, char *header, int ea,
// Salt for header key derivation
if (!RandgetBytes (hwndDlg, keyInfo.salt, PKCS5_SALT_SIZE, !bWipeMode))
- return ERR_CIPHER_INIT_WEAK_KEY;
+ {
+ crypto_close (cryptoInfo);
+ return ERR_CIPHER_INIT_WEAK_KEY;
+ }
- // PBKDF2 (PKCS5) is used to derive primary header key(s) and secondary header key(s) (XTS) from the password/keyfiles
- switch (pkcs5_prf)
+ if (password)
{
- case SHA512:
- derive_key_sha512 (keyInfo.userKey, keyInfo.keyLength, keyInfo.salt,
- PKCS5_SALT_SIZE, keyInfo.noIterations, dk, GetMaxPkcs5OutSize());
- break;
-
- case SHA256:
- derive_key_sha256 (keyInfo.userKey, keyInfo.keyLength, keyInfo.salt,
- PKCS5_SALT_SIZE, keyInfo.noIterations, dk, GetMaxPkcs5OutSize());
- break;
-
- case RIPEMD160:
- derive_key_ripemd160 (keyInfo.userKey, keyInfo.keyLength, keyInfo.salt,
- PKCS5_SALT_SIZE, keyInfo.noIterations, dk, GetMaxPkcs5OutSize());
- break;
-
- case WHIRLPOOL:
- derive_key_whirlpool (keyInfo.userKey, keyInfo.keyLength, keyInfo.salt,
- PKCS5_SALT_SIZE, keyInfo.noIterations, dk, GetMaxPkcs5OutSize());
- break;
+ // PBKDF2 (PKCS5) is used to derive primary header key(s) and secondary header key(s) (XTS) from the password/keyfiles
+ switch (pkcs5_prf)
+ {
+ case SHA512:
+ derive_key_sha512 (keyInfo.userKey, keyInfo.keyLength, keyInfo.salt,
+ PKCS5_SALT_SIZE, keyInfo.noIterations, dk, GetMaxPkcs5OutSize());
+ break;
- default:
- // Unknown/wrong ID
- TC_THROW_FATAL_EXCEPTION;
+ case SHA256:
+ derive_key_sha256 (keyInfo.userKey, keyInfo.keyLength, keyInfo.salt,
+ PKCS5_SALT_SIZE, keyInfo.noIterations, dk, GetMaxPkcs5OutSize());
+ break;
+
+ case RIPEMD160:
+ derive_key_ripemd160 (keyInfo.userKey, keyInfo.keyLength, keyInfo.salt,
+ PKCS5_SALT_SIZE, keyInfo.noIterations, dk, GetMaxPkcs5OutSize());
+ break;
+
+ case WHIRLPOOL:
+ derive_key_whirlpool (keyInfo.userKey, keyInfo.keyLength, keyInfo.salt,
+ PKCS5_SALT_SIZE, keyInfo.noIterations, dk, GetMaxPkcs5OutSize());
+ break;
+
+
+ default:
+ // Unknown/wrong ID
+ crypto_close (cryptoInfo);
+ TC_THROW_FATAL_EXCEPTION;
+ }
+ }
+ else
+ {
+ // generate a random key
+ if (!RandgetBytes(hwndDlg, dk, GetMaxPkcs5OutSize(), !bWipeMode))
+ {
+ crypto_close (cryptoInfo);
+ return ERR_CIPHER_INIT_WEAK_KEY;
+ }
}
/* Header setup */
@@ -950,6 +978,7 @@ int CreateVolumeHeaderInMemory (HWND hwndDlg, BOOL bBoot, char *header, int ea,
|| sectorSize > TC_MAX_VOLUME_SECTOR_SIZE
|| sectorSize % ENCRYPTION_DATA_UNIT_SIZE != 0)
{
+ crypto_close (cryptoInfo);
TC_THROW_FATAL_EXCEPTION;
}
@@ -978,11 +1007,17 @@ int CreateVolumeHeaderInMemory (HWND hwndDlg, BOOL bBoot, char *header, int ea,
retVal = EAInit (cryptoInfo->ea, dk + primaryKeyOffset, cryptoInfo->ks);
if (retVal != ERR_SUCCESS)
+ {
+ crypto_close (cryptoInfo);
return retVal;
+ }
// Mode of operation
if (!EAInitMode (cryptoInfo))
+ {
+ crypto_close (cryptoInfo);
return ERR_OUTOFMEMORY;
+ }
// Encrypt the entire header (except the salt)
@@ -996,7 +1031,10 @@ int CreateVolumeHeaderInMemory (HWND hwndDlg, BOOL bBoot, char *header, int ea,
// Init with the master key(s)
retVal = EAInit (cryptoInfo->ea, keyInfo.master_keydata + primaryKeyOffset, cryptoInfo->ks);
if (retVal != ERR_SUCCESS)
+ {
+ crypto_close (cryptoInfo);
return retVal;
+ }
memcpy (cryptoInfo->master_keydata, keyInfo.master_keydata, MASTER_KEYDATA_SIZE);
@@ -1010,7 +1048,10 @@ int CreateVolumeHeaderInMemory (HWND hwndDlg, BOOL bBoot, char *header, int ea,
// Mode of operation
if (!EAInitMode (cryptoInfo))
+ {
+ crypto_close (cryptoInfo);
return ERR_OUTOFMEMORY;
+ }
#ifdef VOLFORMAT
diff --git a/src/ExpandVolume/ExpandVolume.c b/src/ExpandVolume/ExpandVolume.c
index abe09557..82c4207e 100644
--- a/src/ExpandVolume/ExpandVolume.c
+++ b/src/ExpandVolume/ExpandVolume.c
@@ -804,7 +804,7 @@ static int ExpandVolume (HWND hwndDlg, wchar_t *lpszVolume, Password *pVolumePas
cryptoInfo->RequiredProgramVersion,
cryptoInfo->HeaderFlags,
cryptoInfo->SectorSize,
- TRUE ); // use slow poll
+ FALSE ); // use slow poll
if (ci != NULL)
crypto_close (ci);
@@ -818,8 +818,7 @@ static int ExpandVolume (HWND hwndDlg, wchar_t *lpszVolume, Password *pVolumePas
goto error;
}
- nStatus = _lwrite ((HFILE) dev, buffer, TC_VOLUME_HEADER_EFFECTIVE_SIZE);
- if (nStatus != TC_VOLUME_HEADER_EFFECTIVE_SIZE)
+ if (!WriteEffectiveVolumeHeader (bDevice, dev, buffer))
{
nStatus = ERR_OS_ERROR;
goto error;
@@ -835,9 +834,51 @@ static int ExpandVolume (HWND hwndDlg, wchar_t *lpszVolume, Password *pVolumePas
)
{
//DebugAddProgressDlgStatus(hwndDlg, L"WriteRandomDataToReservedHeaderAreas() ...\r\n");
+ PCRYPTO_INFO dummyInfo = NULL;
+ LARGE_INTEGER hiddenOffset;
+
nStatus = WriteRandomDataToReservedHeaderAreas (hwndDlg, dev, cryptoInfo, newDataAreaSize, !backupHeader, backupHeader);
if (nStatus != ERR_SUCCESS)
goto error;
+
+ // write fake hidden volume header to protect against attacks that use statistical entropy
+ // analysis to detect presence of hidden volumes
+ hiddenOffset.QuadPart = headerOffset.QuadPart + TC_HIDDEN_VOLUME_HEADER_OFFSET;
+
+ nStatus = CreateVolumeHeaderInMemory (hwndDlg, FALSE,
+ buffer,
+ cryptoInfo->ea,
+ cryptoInfo->mode,
+ NULL,
+ 0,
+ 0,
+ NULL,
+ &dummyInfo,
+ newDataAreaSize,
+ newDataAreaSize, // hiddenVolumeSize
+ cryptoInfo->EncryptedAreaStart.Value,
+ newDataAreaSize,
+ cryptoInfo->RequiredProgramVersion,
+ cryptoInfo->HeaderFlags,
+ cryptoInfo->SectorSize,
+ FALSE ); // use slow poll
+
+ if (nStatus != ERR_SUCCESS)
+ goto error;
+
+ crypto_close (dummyInfo);
+
+ if (!SetFilePointerEx ((HANDLE) dev, hiddenOffset, NULL, FILE_BEGIN))
+ {
+ nStatus = ERR_OS_ERROR;
+ goto error;
+ }
+
+ if (!WriteEffectiveVolumeHeader (bDevice, dev, buffer))
+ {
+ nStatus = ERR_OS_ERROR;
+ goto error;
+ }
}
FlushFileBuffers (dev);
diff --git a/src/Format/InPlace.c b/src/Format/InPlace.c
index d3b3212b..f37cb8be 100644
--- a/src/Format/InPlace.c
+++ b/src/Format/InPlace.c
@@ -566,6 +566,8 @@ int EncryptPartitionInPlaceBegin (volatile FORMAT_VOL_PARAMETERS *volParams, vol
// Prepare the backup header
for (int wipePass = 0; wipePass < (wipeAlgorithm == TC_WIPE_NONE ? 1 : PRAND_HEADER_WIPE_PASSES); wipePass++)
{
+ PCRYPTO_INFO dummyInfo = NULL;
+
nStatus = CreateVolumeHeaderInMemory (hwndDlg, FALSE,
header,
volParams->ea,
@@ -607,6 +609,47 @@ int EncryptPartitionInPlaceBegin (volatile FORMAT_VOL_PARAMETERS *volParams, vol
if (nStatus != ERR_SUCCESS)
goto closing_seq;
+
+ // write fake hidden volume header to protect against attacks that use statistical entropy
+ // analysis to detect presence of hidden volumes
+ nStatus = CreateVolumeHeaderInMemory (hwndDlg, FALSE,
+ header,
+ volParams->ea,
+ FIRST_MODE_OF_OPERATION_ID,
+ NULL,
+ 0,
+ 0,
+ NULL,
+ &dummyInfo,
+ dataAreaSize,
+ dataAreaSize,
+ TC_VOLUME_DATA_OFFSET + dataAreaSize, // Start of the encrypted area = the first byte of the backup heeader (encrypting from the end)
+ dataAreaSize, // No data is encrypted yet
+ 0,
+ volParams->headerFlags | TC_HEADER_FLAG_NONSYS_INPLACE_ENC,
+ volParams->sectorSize,
+ wipeAlgorithm == TC_WIPE_NONE ? FALSE : (wipePass < PRAND_HEADER_WIPE_PASSES - 1));
+
+ if (nStatus != ERR_SUCCESS)
+ goto closing_seq;
+
+ crypto_close (dummyInfo);
+
+ offset.QuadPart += TC_HIDDEN_VOLUME_HEADER_OFFSET;
+
+ if (!SetFilePointerEx (dev, offset, NULL, FILE_BEGIN))
+ {
+ nStatus = ERR_OS_ERROR;
+ goto closing_seq;
+ }
+
+ // Write the fake hidden backup header to the partition
+ if (!WriteEffectiveVolumeHeader (TRUE, dev, (byte *) header))
+ {
+ nStatus = ERR_OS_ERROR;
+ goto closing_seq;
+ }
+
}
@@ -1045,6 +1088,8 @@ inplace_enc_read:
for (int wipePass = 0; wipePass < (wipeAlgorithm == TC_WIPE_NONE ? 1 : PRAND_HEADER_WIPE_PASSES); wipePass++)
{
+ PCRYPTO_INFO dummyInfo = NULL;
+
nStatus = CreateVolumeHeaderInMemory (hwndDlg, FALSE,
header,
headerCryptoInfo->ea,
@@ -1081,6 +1126,40 @@ inplace_enc_read:
if (nStatus != ERR_SUCCESS)
goto closing_seq;
+
+ // write fake hidden volume header to protect against attacks that use statistical entropy
+ // analysis to detect presence of hidden volumes
+ nStatus = CreateVolumeHeaderInMemory (hwndDlg, FALSE,
+ header,
+ headerCryptoInfo->ea,
+ headerCryptoInfo->mode,
+ NULL,
+ 0,
+ 0,
+ NULL,
+ &dummyInfo,
+ masterCryptoInfo->VolumeSize.Value,
+ masterCryptoInfo->VolumeSize.Value,
+ masterCryptoInfo->EncryptedAreaStart.Value,
+ masterCryptoInfo->EncryptedAreaLength.Value,
+ masterCryptoInfo->RequiredProgramVersion,
+ masterCryptoInfo->HeaderFlags | TC_HEADER_FLAG_NONSYS_INPLACE_ENC,
+ masterCryptoInfo->SectorSize,
+ wipeAlgorithm == TC_WIPE_NONE ? FALSE : (wipePass < PRAND_HEADER_WIPE_PASSES - 1));
+
+ if (nStatus != ERR_SUCCESS)
+ goto closing_seq;
+
+ crypto_close (dummyInfo);
+
+ offset.QuadPart += TC_HIDDEN_VOLUME_HEADER_OFFSET;
+
+ if (SetFilePointerEx (dev, offset, NULL, FILE_BEGIN) == 0
+ || !WriteEffectiveVolumeHeader (TRUE, dev, (byte *) header))
+ {
+ nStatus = ERR_OS_ERROR;
+ goto closing_seq;
+ }
}
// Update the configuration files