diff options
Diffstat (limited to 'src/Common/BootEncryption.cpp')
-rw-r--r-- | src/Common/BootEncryption.cpp | 5626 |
1 files changed, 2813 insertions, 2813 deletions
diff --git a/src/Common/BootEncryption.cpp b/src/Common/BootEncryption.cpp index 851d7622..73b64458 100644 --- a/src/Common/BootEncryption.cpp +++ b/src/Common/BootEncryption.cpp @@ -1,2813 +1,2813 @@ -/*
- Derived from source code of TrueCrypt 7.1a, which is
- Copyright (c) 2008-2012 TrueCrypt Developers Association and which is governed
- by the TrueCrypt License 3.0.
-
- Modifications and additions to the original source code (contained in this file)
- and all other portions of this file are Copyright (c) 2013-2016 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 "Platform/Finally.h"
-#include "Platform/ForEach.h"
-#include <devguid.h>
-#include <io.h>
-#include <shlobj.h>
-#include <atlbase.h>
-#include "BootEncryption.h"
-#include "Boot/Windows/BootCommon.h"
-#include "Common/Resource.h"
-#include "Crc.h"
-#include "Crypto.h"
-#include "Dlgcode.h"
-#include "Endian.h"
-#include "Language.h"
-#include "Random.h"
-#include "Registry.h"
-#include "Volumes.h"
-
-#ifdef VOLFORMAT
-#include "Format/FormatCom.h"
-#elif defined (TCMOUNT)
-#include "Mount/MainCom.h"
-#endif
-
-#include <Strsafe.h>
-
-namespace VeraCrypt
-{
-#if !defined (SETUP)
-
- class Elevator
- {
- public:
-
- static void AddReference ()
- {
- ++ReferenceCount;
- }
-
-
- static void CallDriver (DWORD ioctl, void *input, DWORD inputSize, void *output, DWORD outputSize)
- {
- Elevate();
-
- CComBSTR inputBstr;
- if (input && inputBstr.AppendBytes ((const char *) input, inputSize) != S_OK)
- throw ParameterIncorrect (SRC_POS);
-
- CComBSTR outputBstr;
- if (output && outputBstr.AppendBytes ((const char *) output, outputSize) != S_OK)
- throw ParameterIncorrect (SRC_POS);
-
- DWORD result = ElevatedComInstance->CallDriver (ioctl, inputBstr, &outputBstr);
-
- if (output)
- memcpy (output, *(void **) &outputBstr, outputSize);
-
- if (result != ERROR_SUCCESS)
- {
- SetLastError (result);
- throw SystemException(SRC_POS);
- }
- }
-
- static void CopyFile (const wstring &sourceFile, const wstring &destinationFile)
- {
- Elevate();
- DWORD result;
- CComBSTR sourceFileBstr, destinationFileBstr;
- BSTR bstr = W2BSTR(sourceFile.c_str());
- if (bstr)
- {
- sourceFileBstr.Attach (bstr);
-
- bstr = W2BSTR(destinationFile.c_str());
- if (bstr)
- {
- destinationFileBstr.Attach (bstr);
- result = ElevatedComInstance->CopyFile (sourceFileBstr, destinationFileBstr);
- }
- else
- {
- result = ERROR_OUTOFMEMORY;
- }
- }
- else
- {
- result = ERROR_OUTOFMEMORY;
- }
-
- if (result != ERROR_SUCCESS)
- {
- SetLastError (result);
- throw SystemException(SRC_POS);
- }
- }
-
- static void DeleteFile (const wstring &file)
- {
- Elevate();
- CComBSTR fileBstr;
- DWORD result;
- BSTR bstr = W2BSTR(file.c_str());
- if (bstr)
- {
- fileBstr.Attach (bstr);
- result = ElevatedComInstance->DeleteFile (fileBstr);
- }
- else
- {
- result = ERROR_OUTOFMEMORY;
- }
-
- if (result != ERROR_SUCCESS)
- {
- SetLastError (result);
- throw SystemException(SRC_POS);
- }
- }
-
- static void ReadWriteFile (BOOL write, BOOL device, const wstring &filePath, byte *buffer, uint64 offset, uint32 size, DWORD *sizeDone)
- {
- Elevate();
-
- DWORD result;
- CComBSTR bufferBstr, fileBstr;
- if (bufferBstr.AppendBytes ((const char *) buffer, size) != S_OK)
- throw ParameterIncorrect (SRC_POS);
- BSTR bstr = W2BSTR(filePath.c_str());
- if (bstr)
- {
- fileBstr.Attach (bstr);
- result = ElevatedComInstance->ReadWriteFile (write, device, fileBstr, &bufferBstr, offset, size, sizeDone);
- }
- else
- {
- result = ERROR_OUTOFMEMORY;
- }
-
- if (result != ERROR_SUCCESS)
- {
- SetLastError (result);
- throw SystemException(SRC_POS);
- }
-
- if (!write)
- memcpy (buffer, (BYTE *) bufferBstr.m_str, size);
- }
-
- static BOOL IsPagingFileActive (BOOL checkNonWindowsPartitionsOnly)
- {
- Elevate();
-
- return ElevatedComInstance->IsPagingFileActive (checkNonWindowsPartitionsOnly);
- }
-
- static void WriteLocalMachineRegistryDwordValue (wchar_t *keyPath, wchar_t *valueName, DWORD value)
- {
- Elevate();
- DWORD result;
- CComBSTR keyPathBstr, valueNameBstr;
- BSTR bstr = W2BSTR(keyPath);
- if (bstr)
- {
- keyPathBstr.Attach (bstr);
-
- bstr = W2BSTR(valueName);
- if (bstr)
- {
- valueNameBstr.Attach (bstr);
-
- result = ElevatedComInstance->WriteLocalMachineRegistryDwordValue (keyPathBstr, valueNameBstr, value);
- }
- else
- {
- result = ERROR_OUTOFMEMORY;
- }
- }
- else
- {
- result = ERROR_OUTOFMEMORY;
- }
-
- if (result != ERROR_SUCCESS)
- {
- SetLastError (result);
- throw SystemException(SRC_POS);
- }
- }
-
- static void RegisterFilterDriver (bool registerDriver, BootEncryption::FilterType filterType)
- {
- Elevate();
-
- DWORD result = ElevatedComInstance->RegisterFilterDriver (registerDriver ? TRUE : FALSE, filterType);
- if (result != ERROR_SUCCESS)
- {
- SetLastError (result);
- throw SystemException(SRC_POS);
- }
- }
-
- static void RegisterSystemFavoritesService (BOOL registerService)
- {
- Elevate();
-
- DWORD result = ElevatedComInstance->RegisterSystemFavoritesService (registerService);
- if (result != ERROR_SUCCESS)
- {
- SetLastError (result);
- throw SystemException(SRC_POS);
- }
- }
-
- static void Release ()
- {
- if (--ReferenceCount == 0 && ElevatedComInstance)
- {
- ElevatedComInstance->Release();
- ElevatedComInstance = nullptr;
- CoUninitialize ();
- }
- }
-
- static void SetDriverServiceStartType (DWORD startType)
- {
- Elevate();
-
- DWORD result = ElevatedComInstance->SetDriverServiceStartType (startType);
- if (result != ERROR_SUCCESS)
- {
- SetLastError (result);
- throw SystemException(SRC_POS);
- }
- }
-
- protected:
- static void Elevate ()
- {
- if (IsAdmin())
- {
- SetLastError (ERROR_ACCESS_DENIED);
- throw SystemException(SRC_POS);
- }
-
- if (!ElevatedComInstance || ElevatedComInstanceThreadId != GetCurrentThreadId())
- {
- CoInitialize (NULL);
- ElevatedComInstance = GetElevatedInstance (GetActiveWindow() ? GetActiveWindow() : MainDlg);
- ElevatedComInstanceThreadId = GetCurrentThreadId();
- }
- }
-
-#if defined (TCMOUNT)
- static ITrueCryptMainCom *ElevatedComInstance;
-#elif defined (VOLFORMAT)
- static ITrueCryptFormatCom *ElevatedComInstance;
-#endif
- static DWORD ElevatedComInstanceThreadId;
- static int ReferenceCount;
- };
-
-#if defined (TCMOUNT)
- ITrueCryptMainCom *Elevator::ElevatedComInstance;
-#elif defined (VOLFORMAT)
- ITrueCryptFormatCom *Elevator::ElevatedComInstance;
-#endif
- DWORD Elevator::ElevatedComInstanceThreadId;
- int Elevator::ReferenceCount = 0;
-
-#else // SETUP
-
- class Elevator
- {
- public:
- static void AddReference () { }
- static void CallDriver (DWORD ioctl, void *input, DWORD inputSize, void *output, DWORD outputSize) { throw ParameterIncorrect (SRC_POS); }
- static void ReadWriteFile (BOOL write, BOOL device, const wstring &filePath, byte *buffer, uint64 offset, uint32 size, DWORD *sizeDone) { throw ParameterIncorrect (SRC_POS); }
- static void RegisterFilterDriver (bool registerDriver, BootEncryption::FilterType filterType) { throw ParameterIncorrect (SRC_POS); }
- static void Release () { }
- static void SetDriverServiceStartType (DWORD startType) { throw ParameterIncorrect (SRC_POS); }
- };
-
-#endif // SETUP
-
-
- File::File (wstring path, bool readOnly, bool create) : Elevated (false), FileOpen (false), LastError(0)
- {
- Handle = CreateFile (path.c_str(),
- readOnly ? GENERIC_READ : GENERIC_READ | GENERIC_WRITE,
- FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, create ? CREATE_ALWAYS : OPEN_EXISTING,
- FILE_FLAG_RANDOM_ACCESS | FILE_FLAG_WRITE_THROUGH, NULL);
-
- if (Handle != INVALID_HANDLE_VALUE)
- {
- FileOpen = true;
- }
- else
- {
- LastError = GetLastError();
- if (LastError == ERROR_ACCESS_DENIED && IsUacSupported())
- {
- Elevated = true;
- FileOpen = true;
- }
- }
-
- FilePointerPosition = 0;
- IsDevice = false;
- Path = path;
- }
-
- void File::Close ()
- {
- if (Handle != INVALID_HANDLE_VALUE)
- {
- CloseHandle (Handle);
- Handle = INVALID_HANDLE_VALUE;
- }
-
- FileOpen = false;
- }
-
- DWORD File::Read (byte *buffer, DWORD size)
- {
- DWORD bytesRead;
-
- if (!FileOpen)
- {
- SetLastError (LastError);
- throw SystemException (SRC_POS);
- }
-
- if (Elevated)
- {
- DWORD bytesRead;
-
- Elevator::ReadWriteFile (false, IsDevice, Path, buffer, FilePointerPosition, size, &bytesRead);
- FilePointerPosition += bytesRead;
- return bytesRead;
- }
-
- throw_sys_if (!ReadFile (Handle, buffer, size, &bytesRead, NULL));
- return bytesRead;
- }
-
- void File::SeekAt (int64 position)
- {
- if (!FileOpen)
- {
- SetLastError (LastError);
- throw SystemException (SRC_POS);
- }
-
- FilePointerPosition = position;
-
- if (!Elevated)
- {
- LARGE_INTEGER pos;
- pos.QuadPart = position;
- throw_sys_if (!SetFilePointerEx (Handle, pos, NULL, FILE_BEGIN));
- }
- }
-
- void File::Write (byte *buffer, DWORD size)
- {
- DWORD bytesWritten;
-
- if (!FileOpen)
- {
- SetLastError (LastError);
- throw SystemException (SRC_POS);
- }
-
- try
- {
- if (Elevated)
- {
- Elevator::ReadWriteFile (true, IsDevice, Path, buffer, FilePointerPosition, size, &bytesWritten);
- FilePointerPosition += bytesWritten;
- throw_sys_if (bytesWritten != size);
- }
- else
- {
- throw_sys_if (!WriteFile (Handle, buffer, size, &bytesWritten, NULL) || bytesWritten != size);
- }
- }
- catch (SystemException &e)
- {
- if (!IsDevice || e.ErrorCode != ERROR_WRITE_PROTECT)
- throw;
-
- BootEncryption bootEnc (NULL);
-
- while (size >= TC_SECTOR_SIZE_BIOS)
- {
- bootEnc.WriteBootDriveSector (FilePointerPosition, buffer);
-
- FilePointerPosition += TC_SECTOR_SIZE_BIOS;
- buffer += TC_SECTOR_SIZE_BIOS;
- size -= TC_SECTOR_SIZE_BIOS;
- }
- }
- }
-
- void Show (HWND parent, const wstring &str)
- {
- MessageBox (parent, str.c_str(), NULL, 0);
- }
-
-
- Device::Device (wstring path, bool readOnly)
- {
- FileOpen = false;
- Elevated = false;
-
- Handle = CreateFile ((wstring (L"\\\\.\\") + path).c_str(),
- readOnly ? GENERIC_READ : GENERIC_READ | GENERIC_WRITE,
- FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
- FILE_FLAG_RANDOM_ACCESS | FILE_FLAG_WRITE_THROUGH, NULL);
-
- if (Handle != INVALID_HANDLE_VALUE)
- {
- FileOpen = true;
- }
- else
- {
- LastError = GetLastError ();
- if (LastError == ERROR_ACCESS_DENIED && IsUacSupported())
- {
- Elevated = true;
- FileOpen = true;
- }
- }
-
- FilePointerPosition = 0;
- IsDevice = true;
- Path = path;
- }
-
-
- BootEncryption::BootEncryption (HWND parent)
- : DriveConfigValid (false),
- ParentWindow (parent),
- RealSystemDriveSizeValid (false),
- RescueIsoImage (nullptr),
- RescueVolumeHeaderValid (false),
- SelectedEncryptionAlgorithmId (0),
- SelectedPrfAlgorithmId (0),
- VolumeHeaderValid (false)
- {
- HiddenOSCandidatePartition.IsGPT = FALSE;
- HiddenOSCandidatePartition.Number = (size_t) -1;
- DriveConfig.DriveNumber = -1;
- DriveConfig.ExtraBootPartitionPresent = false;
- DriveConfig.SystemLoaderPresent = false;
- DriveConfig.InitialUnallocatedSpace = 0;
- DriveConfig.TotalUnallocatedSpace = 0;
- Elevator::AddReference();
- }
-
-
- BootEncryption::~BootEncryption ()
- {
- if (RescueIsoImage)
- delete[] RescueIsoImage;
-
- Elevator::Release();
- }
-
-
- void BootEncryption::CallDriver (DWORD ioctl, void *input, DWORD inputSize, void *output, DWORD outputSize)
- {
- try
- {
- DWORD bytesReturned;
- throw_sys_if (!DeviceIoControl (hDriver, ioctl, input, inputSize, output, outputSize, &bytesReturned, NULL));
- }
- catch (SystemException &)
- {
- if (GetLastError() == ERROR_ACCESS_DENIED && IsUacSupported())
- Elevator::CallDriver (ioctl, input, inputSize, output, outputSize);
- else
- throw;
- }
- }
-
-
- // Finds the first partition physically located behind the active one and returns its properties
- Partition BootEncryption::GetPartitionForHiddenOS ()
- {
- Partition candidatePartition;
-
- memset (&candidatePartition, 0, sizeof(candidatePartition));
-
- // The user may have modified/added/deleted partitions since the time the partition table was last scanned
- InvalidateCachedSysDriveProperties();
-
- SystemDriveConfiguration config = GetSystemDriveConfiguration ();
- bool activePartitionFound = false;
- bool candidateForHiddenOSFound = false;
-
- if (config.SystemPartition.IsGPT)
- throw ParameterIncorrect (SRC_POS); // It is assumed that CheckRequirements() had been called
-
- // Find the first active partition on the system drive
- foreach (const Partition &partition, config.Partitions)
- {
- if (partition.Info.BootIndicator)
- {
- if (partition.Info.PartitionNumber != config.SystemPartition.Number)
- {
- // If there is an extra boot partition, the system partition must be located right behind it
- if (IsOSAtLeast (WIN_7) && config.ExtraBootPartitionPresent)
- {
- int64 minOffsetFound = config.DrivePartition.Info.PartitionLength.QuadPart;
- Partition bootPartition = partition;
- Partition partitionBehindBoot;
-
- foreach (const Partition &partition, config.Partitions)
- {
- if (partition.Info.StartingOffset.QuadPart > bootPartition.Info.StartingOffset.QuadPart
- && partition.Info.StartingOffset.QuadPart < minOffsetFound)
- {
- minOffsetFound = partition.Info.StartingOffset.QuadPart;
- partitionBehindBoot = partition;
- }
- }
-
- if (minOffsetFound != config.DrivePartition.Info.PartitionLength.QuadPart
- && partitionBehindBoot.Number == config.SystemPartition.Number)
- {
- activePartitionFound = true;
- break;
- }
- }
-
- throw ErrorException (wstring (GetString ("SYSTEM_PARTITION_NOT_ACTIVE"))
- + GetRemarksOnHiddenOS(), SRC_POS);
- }
-
- activePartitionFound = true;
- break;
- }
- }
-
- /* WARNING: Note that the partition number at the end of a device path (\Device\HarddiskY\PartitionX) must
- NOT be used to find the first partition physically located behind the active one. The reason is that the
- user may have deleted and created partitions during this session and e.g. the second partition could have
- a higer number than the third one. */
-
-
- // Find the first partition physically located behind the active partition
- if (activePartitionFound)
- {
- int64 minOffsetFound = config.DrivePartition.Info.PartitionLength.QuadPart;
-
- foreach (const Partition &partition, config.Partitions)
- {
- if (partition.Info.StartingOffset.QuadPart > config.SystemPartition.Info.StartingOffset.QuadPart
- && partition.Info.StartingOffset.QuadPart < minOffsetFound)
- {
- minOffsetFound = partition.Info.StartingOffset.QuadPart;
-
- candidatePartition = partition;
-
- candidateForHiddenOSFound = true;
- }
- }
-
- if (!candidateForHiddenOSFound)
- {
- throw ErrorException (wstring (GetString ("NO_PARTITION_FOLLOWS_BOOT_PARTITION"))
- + GetRemarksOnHiddenOS(), SRC_POS);
- }
-
- if (config.SystemPartition.Info.PartitionLength.QuadPart > TC_MAX_FAT_SECTOR_COUNT * TC_SECTOR_SIZE_BIOS)
- {
- if ((double) candidatePartition.Info.PartitionLength.QuadPart / config.SystemPartition.Info.PartitionLength.QuadPart < MIN_HIDDENOS_DECOY_PARTITION_SIZE_RATIO_NTFS)
- {
- throw ErrorException (wstring (GetString ("PARTITION_TOO_SMALL_FOR_HIDDEN_OS_NTFS"))
- + GetRemarksOnHiddenOS(), SRC_POS);
- }
- }
- else if ((double) candidatePartition.Info.PartitionLength.QuadPart / config.SystemPartition.Info.PartitionLength.QuadPart < MIN_HIDDENOS_DECOY_PARTITION_SIZE_RATIO_FAT)
- {
- throw ErrorException (wstring (GetString ("PARTITION_TOO_SMALL_FOR_HIDDEN_OS"))
- + GetRemarksOnHiddenOS(), SRC_POS);
- }
- }
- else
- {
- // No active partition on the system drive
- throw ErrorException ("SYSTEM_PARTITION_NOT_ACTIVE", SRC_POS);
- }
-
- HiddenOSCandidatePartition = candidatePartition;
- return candidatePartition;
- }
-
-
- DWORD BootEncryption::GetDriverServiceStartType ()
- {
- DWORD startType;
- throw_sys_if (!ReadLocalMachineRegistryDword (L"SYSTEM\\CurrentControlSet\\Services\\veracrypt", L"Start", &startType));
- return startType;
- }
-
-
- wstring BootEncryption::GetRemarksOnHiddenOS ()
- {
- return (wstring (L"\n\n")
- + GetString ("TWO_SYSTEMS_IN_ONE_PARTITION_REMARK")
- + L"\n\n"
- + GetString ("FOR_MORE_INFO_ON_PARTITIONS"));
- }
-
-
- void BootEncryption::SetDriverServiceStartType (DWORD startType)
- {
- if (!IsAdmin() && IsUacSupported())
- {
- Elevator::SetDriverServiceStartType (startType);
- return;
- }
-
- BOOL startOnBoot = (startType == SERVICE_BOOT_START);
-
- SC_HANDLE serviceManager = OpenSCManager (NULL, NULL, SC_MANAGER_ALL_ACCESS);
- throw_sys_if (!serviceManager);
-
- finally_do_arg (SC_HANDLE, serviceManager, { CloseServiceHandle (finally_arg); });
-
- SC_HANDLE service = OpenService (serviceManager, L"veracrypt", SERVICE_CHANGE_CONFIG);
- throw_sys_if (!service);
-
- finally_do_arg (SC_HANDLE, service, { CloseServiceHandle (finally_arg); });
-
- // Windows versions preceding Vista can be installed on FAT filesystem which does not
- // support long filenames during boot. Convert the driver path to short form if required.
- wstring driverPath;
- if (startOnBoot && !IsOSAtLeast (WIN_VISTA))
- {
- wchar_t pathBuf[MAX_PATH];
- wchar_t filesystem[128];
-
- wstring path (GetWindowsDirectory());
- path += L"\\drivers\\veracrypt.sys";
-
- if (GetVolumePathName (path.c_str(), pathBuf, ARRAYSIZE (pathBuf))
- && GetVolumeInformation (pathBuf, NULL, 0, NULL, NULL, NULL, filesystem, ARRAYSIZE(filesystem))
- && wmemcmp (filesystem, L"FAT", 3) == 0)
- {
- throw_sys_if (GetShortPathName (path.c_str(), pathBuf, ARRAYSIZE (pathBuf)) == 0);
-
- // Convert absolute path to relative to the Windows directory
- driverPath = pathBuf;
- driverPath = driverPath.substr (driverPath.rfind (L"\\", driverPath.rfind (L"\\", driverPath.rfind (L"\\") - 1) - 1) + 1);
- }
- }
-
- throw_sys_if (!ChangeServiceConfig (service, SERVICE_NO_CHANGE, SERVICE_NO_CHANGE,
- startOnBoot ? SERVICE_ERROR_SEVERE : SERVICE_ERROR_NORMAL,
- driverPath.empty() ? NULL : driverPath.c_str(),
- startOnBoot ? L"Filter" : NULL,
- NULL, NULL, NULL, NULL, NULL));
-
- // ChangeServiceConfig() rejects SERVICE_BOOT_START with ERROR_INVALID_PARAMETER
- throw_sys_if (!WriteLocalMachineRegistryDword (L"SYSTEM\\CurrentControlSet\\Services\\veracrypt", L"Start", startType));
- }
-
-
- void BootEncryption::ProbeRealSystemDriveSize ()
- {
- if (RealSystemDriveSizeValid)
- return;
-
- GetSystemDriveConfiguration();
-
- ProbeRealDriveSizeRequest request;
- StringCchCopyW (request.DeviceName, ARRAYSIZE (request.DeviceName), DriveConfig.DrivePartition.DevicePath.c_str());
-
- CallDriver (TC_IOCTL_PROBE_REAL_DRIVE_SIZE, &request, sizeof (request), &request, sizeof (request));
- DriveConfig.DrivePartition.Info.PartitionLength = request.RealDriveSize;
-
- RealSystemDriveSizeValid = true;
-
- if (request.TimeOut)
- throw TimeOut (SRC_POS);
- }
-
-
- void BootEncryption::InvalidateCachedSysDriveProperties ()
- {
- DriveConfigValid = false;
- RealSystemDriveSizeValid = false;
- }
-
-
- PartitionList BootEncryption::GetDrivePartitions (int driveNumber)
- {
- PartitionList partList;
-
- for (int partNumber = 0; partNumber < 64; ++partNumber)
- {
- wstringstream partPath;
- partPath << L"\\Device\\Harddisk" << driveNumber << L"\\Partition" << partNumber;
-
- DISK_PARTITION_INFO_STRUCT diskPartInfo = {0};
- StringCchCopyW (diskPartInfo.deviceName, ARRAYSIZE (diskPartInfo.deviceName), partPath.str().c_str());
-
- try
- {
- CallDriver (TC_IOCTL_GET_DRIVE_PARTITION_INFO, &diskPartInfo, sizeof (diskPartInfo), &diskPartInfo, sizeof (diskPartInfo));
- }
- catch (...)
- {
- continue;
- }
-
- if ( (diskPartInfo.IsGPT == TRUE || diskPartInfo.IsGPT == FALSE)
- && (diskPartInfo.IsDynamic == TRUE || diskPartInfo.IsDynamic == FALSE)
- && (diskPartInfo.partInfo.BootIndicator == TRUE || diskPartInfo.partInfo.BootIndicator == FALSE)
- && (diskPartInfo.partInfo.RecognizedPartition == TRUE || diskPartInfo.partInfo.RecognizedPartition == FALSE)
- && (diskPartInfo.partInfo.RewritePartition == TRUE || diskPartInfo.partInfo.RewritePartition == FALSE)
- && (diskPartInfo.partInfo.StartingOffset.QuadPart >= 0)
- && (diskPartInfo.partInfo.PartitionLength.QuadPart >= 0)
- )
- {
- Partition part;
- part.DevicePath = partPath.str();
- part.Number = partNumber;
- part.Info = diskPartInfo.partInfo;
- part.IsGPT = diskPartInfo.IsGPT;
-
- // Mount point
- int driveNumber = GetDiskDeviceDriveLetter ((wchar_t *) partPath.str().c_str());
-
- if (driveNumber >= 0)
- {
- part.MountPoint += (wchar_t) (driveNumber + L'A');
- part.MountPoint += L":";
- }
-
- // Volume ID
- wchar_t volumePath[TC_MAX_PATH];
- if (ResolveSymbolicLink ((wchar_t *) partPath.str().c_str(), volumePath, sizeof(volumePath)))
- {
- wchar_t volumeName[TC_MAX_PATH];
- HANDLE fh = FindFirstVolumeW (volumeName, array_capacity (volumeName));
- if (fh != INVALID_HANDLE_VALUE)
- {
- do
- {
- wstring volumeNameStr = volumeName;
- wchar_t devicePath[TC_MAX_PATH];
-
- if (QueryDosDeviceW (volumeNameStr.substr (4, volumeNameStr.size() - 1 - 4).c_str(), devicePath, array_capacity (devicePath)) != 0
- && wcscmp (volumePath, devicePath) == 0)
- {
- part.VolumeNameId = volumeName;
- break;
- }
-
- } while (FindNextVolumeW (fh, volumeName, array_capacity (volumeName)));
-
- FindVolumeClose (fh);
- }
- }
-
- partList.push_back (part);
- }
- }
-
- return partList;
- }
-
-
- DISK_GEOMETRY BootEncryption::GetDriveGeometry (int driveNumber)
- {
- wstringstream devName;
- devName << L"\\Device\\Harddisk" << driveNumber << L"\\Partition0";
-
- DISK_GEOMETRY geometry;
- throw_sys_if (!::GetDriveGeometry (devName.str().c_str(), &geometry));
- return geometry;
- }
-
-
- wstring BootEncryption::GetWindowsDirectory ()
- {
- wchar_t buf[MAX_PATH];
- throw_sys_if (GetSystemDirectory (buf, ARRAYSIZE (buf)) == 0);
-
- return wstring (buf);
- }
-
-
-
- uint16 BootEncryption::GetInstalledBootLoaderVersion ()
- {
- uint16 version;
- CallDriver (TC_IOCTL_GET_BOOT_LOADER_VERSION, NULL, 0, &version, sizeof (version));
- return version;
- }
-
- void BootEncryption::GetInstalledBootLoaderFingerprint (byte fingerprint[WHIRLPOOL_DIGESTSIZE + SHA512_DIGESTSIZE])
- {
- BootLoaderFingerprintRequest request;
- CallDriver (VC_IOCTL_GET_BOOT_LOADER_FINGERPRINT, NULL, 0, &request, sizeof (request));
- memcpy (fingerprint, request.Fingerprint, sizeof (request.Fingerprint));
- }
-
- // Note that this does not require admin rights (it just requires the driver to be running)
- bool BootEncryption::IsBootLoaderOnDrive (wchar_t *devicePath)
- {
- try
- {
- OPEN_TEST_STRUCT openTestStruct;
- memset (&openTestStruct, 0, sizeof (openTestStruct));
- DWORD dwResult;
-
- StringCchCopyW (&openTestStruct.wszFileName[0], ARRAYSIZE(openTestStruct.wszFileName),devicePath);
-
- openTestStruct.bDetectTCBootLoader = TRUE;
-
- return (DeviceIoControl (hDriver, TC_IOCTL_OPEN_TEST,
- &openTestStruct, sizeof (OPEN_TEST_STRUCT),
- &openTestStruct, sizeof (OPEN_TEST_STRUCT),
- &dwResult, NULL) && openTestStruct.TCBootLoaderDetected);
- }
- catch (...)
- {
- return false;
- }
- }
-
-
- BootEncryptionStatus BootEncryption::GetStatus ()
- {
- /* IMPORTANT: Do NOT add any potentially time-consuming operations to this function. */
-
- BootEncryptionStatus status;
- CallDriver (TC_IOCTL_GET_BOOT_ENCRYPTION_STATUS, NULL, 0, &status, sizeof (status));
- return status;
- }
-
-
- void BootEncryption::GetVolumeProperties (VOLUME_PROPERTIES_STRUCT *properties)
- {
- if (properties == NULL)
- throw ParameterIncorrect (SRC_POS);
-
- CallDriver (TC_IOCTL_GET_BOOT_DRIVE_VOLUME_PROPERTIES, NULL, 0, properties, sizeof (*properties));
- }
-
-
- bool BootEncryption::IsHiddenSystemRunning ()
- {
- int hiddenSystemStatus;
-
- CallDriver (TC_IOCTL_IS_HIDDEN_SYSTEM_RUNNING, nullptr, 0, &hiddenSystemStatus, sizeof (hiddenSystemStatus));
- return hiddenSystemStatus != 0;
- }
-
-
- bool BootEncryption::SystemDriveContainsPartitionType (byte type)
- {
- Device device (GetSystemDriveConfiguration().DevicePath, true);
- device.CheckOpened (SRC_POS);
-
- byte mbrBuf[TC_SECTOR_SIZE_BIOS];
- device.SeekAt (0);
- device.Read (mbrBuf, sizeof (mbrBuf));
-
- MBR *mbr = reinterpret_cast <MBR *> (mbrBuf);
- if (mbr->Signature != 0xaa55)
- throw ParameterIncorrect (SRC_POS);
-
- for (size_t i = 0; i < array_capacity (mbr->Partitions); ++i)
- {
- if (mbr->Partitions[i].Type == type)
- return true;
- }
-
- return false;
- }
-
-
- bool BootEncryption::SystemDriveContainsExtendedPartition ()
- {
- return SystemDriveContainsPartitionType (PARTITION_EXTENDED) || SystemDriveContainsPartitionType (PARTITION_XINT13_EXTENDED);
- }
-
-
- bool BootEncryption::SystemDriveContainsNonStandardPartitions ()
- {
- for (int partitionType = 1; partitionType <= 0xff; ++partitionType)
- {
- switch (partitionType)
- {
- case PARTITION_FAT_12:
- case PARTITION_FAT_16:
- case PARTITION_EXTENDED:
- case PARTITION_HUGE:
- case PARTITION_IFS:
- case PARTITION_FAT32:
- case PARTITION_FAT32_XINT13:
- case PARTITION_XINT13:
- case PARTITION_XINT13_EXTENDED:
- continue;
- }
-
- if (SystemDriveContainsPartitionType ((byte) partitionType))
- return true;
- }
-
- return false;
- }
-
-
- bool BootEncryption::SystemDriveIsDynamic ()
- {
- GetSystemDriveConfigurationRequest request;
- StringCchCopyW (request.DevicePath, ARRAYSIZE (request.DevicePath), GetSystemDriveConfiguration().DeviceKernelPath.c_str());
-
- CallDriver (TC_IOCTL_GET_SYSTEM_DRIVE_CONFIG, &request, sizeof (request), &request, sizeof (request));
- return request.DriveIsDynamic ? true : false;
- }
-
-
- SystemDriveConfiguration BootEncryption::GetSystemDriveConfiguration ()
- {
- if (DriveConfigValid)
- return DriveConfig;
-
- SystemDriveConfiguration config;
-
- wstring winDir = GetWindowsDirectory();
-
- // Scan all drives
- for (int driveNumber = 0; driveNumber < 32; ++driveNumber)
- {
- bool windowsFound = false;
- bool activePartitionFound = false;
- config.ExtraBootPartitionPresent = false;
- config.SystemLoaderPresent = false;
-
- PartitionList partitions = GetDrivePartitions (driveNumber);
- foreach (const Partition &part, partitions)
- {
- if (!part.MountPoint.empty()
- && (_waccess ((part.MountPoint + L"\\bootmgr").c_str(), 0) == 0 || _waccess ((part.MountPoint + L"\\ntldr").c_str(), 0) == 0))
- {
- config.SystemLoaderPresent = true;
- }
- else if (!part.VolumeNameId.empty()
- && (_waccess ((part.VolumeNameId + L"\\bootmgr").c_str(), 0) == 0 || _waccess ((part.VolumeNameId + L"\\ntldr").c_str(), 0) == 0))
- {
- config.SystemLoaderPresent = true;
- }
-
- if (!windowsFound && !part.MountPoint.empty() && ToUpperCase (winDir).find (ToUpperCase (part.MountPoint)) == 0)
- {
- config.SystemPartition = part;
- windowsFound = true;
- }
-
- if (!activePartitionFound && part.Info.BootIndicator)
- {
- activePartitionFound = true;
-
- if (part.Info.PartitionLength.QuadPart > 0 && part.Info.PartitionLength.QuadPart <= TC_MAX_EXTRA_BOOT_PARTITION_SIZE)
- config.ExtraBootPartitionPresent = true;
- }
- }
-
- if (windowsFound)
- {
- config.DriveNumber = driveNumber;
-
- wstringstream ss;
- ss << L"PhysicalDrive" << driveNumber;
- config.DevicePath = ss.str();
-
- wstringstream kernelPath;
- kernelPath << L"\\Device\\Harddisk" << driveNumber << L"\\Partition0";
- config.DeviceKernelPath = kernelPath.str();
-
- config.DrivePartition = partitions.front();
- partitions.pop_front();
- config.Partitions = partitions;
-
- config.InitialUnallocatedSpace = 0x7fffFFFFffffFFFFull;
- config.TotalUnallocatedSpace = config.DrivePartition.Info.PartitionLength.QuadPart;
-
- foreach (const Partition &part, config.Partitions)
- {
- if (part.Info.StartingOffset.QuadPart < config.InitialUnallocatedSpace)
- config.InitialUnallocatedSpace = part.Info.StartingOffset.QuadPart;
-
- config.TotalUnallocatedSpace -= part.Info.PartitionLength.QuadPart;
- }
-
- DriveConfig = config;
- DriveConfigValid = true;
- return DriveConfig;
- }
- }
-
- throw ParameterIncorrect (SRC_POS);
- }
-
-
- bool BootEncryption::SystemPartitionCoversWholeDrive ()
- {
- SystemDriveConfiguration config = GetSystemDriveConfiguration();
-
- if (IsOSAtLeast (WIN_7)
- && config.Partitions.size() == 2
- && config.ExtraBootPartitionPresent
- && config.DrivePartition.Info.PartitionLength.QuadPart - config.SystemPartition.Info.PartitionLength.QuadPart < 164 * BYTES_PER_MB)
- {
- return true;
- }
-
- return config.Partitions.size() == 1
- && config.DrivePartition.Info.PartitionLength.QuadPart - config.SystemPartition.Info.PartitionLength.QuadPart < 64 * BYTES_PER_MB;
- }
-
-
- uint32 BootEncryption::GetChecksum (byte *data, size_t size)
- {
- uint32 sum = 0;
-
- while (size-- > 0)
- {
- sum += *data++;
- sum = _rotl (sum, 1);
- }
-
- return sum;
- }
-
-
- void BootEncryption::CreateBootLoaderInMemory (byte *buffer, size_t bufferSize, bool rescueDisk, bool hiddenOSCreation)
- {
- if (bufferSize < TC_BOOT_LOADER_AREA_SIZE - TC_BOOT_ENCRYPTION_VOLUME_HEADER_SIZE)
- throw ParameterIncorrect (SRC_POS);
-
- ZeroMemory (buffer, bufferSize);
-
- int ea = 0;
- int pkcs5_prf = 0;
- if (GetStatus().DriveMounted)
- {
- try
- {
- GetBootEncryptionAlgorithmNameRequest request;
- // since we added new field to GetBootEncryptionAlgorithmNameRequest since version 1.0f
- // we zero all the structure so that if we are talking to an older driver, the field
- // BootPrfAlgorithmName will be an empty string
- ZeroMemory(&request, sizeof(request));
- CallDriver (TC_IOCTL_GET_BOOT_ENCRYPTION_ALGORITHM_NAME, NULL, 0, &request, sizeof (request));
-
- if (_stricmp (request.BootEncryptionAlgorithmName, "AES") == 0)
- ea = AES;
- else if (_stricmp (request.BootEncryptionAlgorithmName, "Serpent") == 0)
- ea = SERPENT;
- else if (_stricmp (request.BootEncryptionAlgorithmName, "Twofish") == 0)
- ea = TWOFISH;
-
- if (_stricmp(request.BootPrfAlgorithmName, "SHA-256") == 0)
- pkcs5_prf = SHA256;
- else if (_stricmp(request.BootPrfAlgorithmName, "RIPEMD-160") == 0)
- pkcs5_prf = RIPEMD160;
- else if (strlen(request.BootPrfAlgorithmName) == 0) // case of version < 1.0f
- pkcs5_prf = RIPEMD160;
- }
- catch (...)
- {
- try
- {
- VOLUME_PROPERTIES_STRUCT properties;
- GetVolumeProperties (&properties);
- ea = properties.ea;
- pkcs5_prf = properties.pkcs5;
- }
- catch (...) { }
- }
- }
- else
- {
- if (SelectedEncryptionAlgorithmId == 0 || SelectedPrfAlgorithmId == 0)
- throw ParameterIncorrect (SRC_POS);
-
- ea = SelectedEncryptionAlgorithmId;
- pkcs5_prf = SelectedPrfAlgorithmId;
- }
-
- // Only RIPEMD160 and SHA-256 are supported for boot loader
- if (pkcs5_prf != RIPEMD160 && pkcs5_prf != SHA256)
- throw ParameterIncorrect (SRC_POS);
-
- int bootSectorId = 0;
- int bootLoaderId = 0;
-
- if (pkcs5_prf == SHA256)
- {
- bootSectorId = rescueDisk ? IDR_RESCUE_BOOT_SECTOR_SHA2 : IDR_BOOT_SECTOR_SHA2;
- bootLoaderId = rescueDisk ? IDR_RESCUE_LOADER_SHA2 : IDR_BOOT_LOADER_SHA2;
- }
- else
- {
- bootSectorId = rescueDisk ? IDR_RESCUE_BOOT_SECTOR : IDR_BOOT_SECTOR;
- bootLoaderId = rescueDisk ? IDR_RESCUE_LOADER : IDR_BOOT_LOADER;
- }
-
- switch (ea)
- {
- case AES:
- if (pkcs5_prf == SHA256)
- {
- bootSectorId = rescueDisk ? IDR_RESCUE_BOOT_SECTOR_AES_SHA2 : IDR_BOOT_SECTOR_AES_SHA2;
- bootLoaderId = rescueDisk ? IDR_RESCUE_LOADER_AES_SHA2 : IDR_BOOT_LOADER_AES_SHA2;
- }
- else
- {
- bootSectorId = rescueDisk ? IDR_RESCUE_BOOT_SECTOR_AES : IDR_BOOT_SECTOR_AES;
- bootLoaderId = rescueDisk ? IDR_RESCUE_LOADER_AES : IDR_BOOT_LOADER_AES;
- }
- break;
-
- case SERPENT:
- if (pkcs5_prf == SHA256)
- {
- bootSectorId = rescueDisk ? IDR_RESCUE_BOOT_SECTOR_SERPENT_SHA2 : IDR_BOOT_SECTOR_SERPENT_SHA2;
- bootLoaderId = rescueDisk ? IDR_RESCUE_LOADER_SERPENT_SHA2 : IDR_BOOT_LOADER_SERPENT_SHA2;
- }
- else
- {
- bootSectorId = rescueDisk ? IDR_RESCUE_BOOT_SECTOR_SERPENT : IDR_BOOT_SECTOR_SERPENT;
- bootLoaderId = rescueDisk ? IDR_RESCUE_LOADER_SERPENT : IDR_BOOT_LOADER_SERPENT;
- }
- break;
-
- case TWOFISH:
- if (pkcs5_prf == SHA256)
- {
- bootSectorId = rescueDisk ? IDR_RESCUE_BOOT_SECTOR_TWOFISH_SHA2 : IDR_BOOT_SECTOR_TWOFISH_SHA2;
- bootLoaderId = rescueDisk ? IDR_RESCUE_LOADER_TWOFISH_SHA2 : IDR_BOOT_LOADER_TWOFISH_SHA2;
- }
- else
- {
- bootSectorId = rescueDisk ? IDR_RESCUE_BOOT_SECTOR_TWOFISH : IDR_BOOT_SECTOR_TWOFISH;
- bootLoaderId = rescueDisk ? IDR_RESCUE_LOADER_TWOFISH : IDR_BOOT_LOADER_TWOFISH;
- }
- break;
- }
-
- // Boot sector
- DWORD size;
- byte *bootSecResourceImg = MapResource (L"BIN", bootSectorId, &size);
- if (!bootSecResourceImg || size != TC_SECTOR_SIZE_BIOS)
- throw ParameterIncorrect (SRC_POS);
-
- memcpy (buffer, bootSecResourceImg, size);
-
- *(uint16 *) (buffer + TC_BOOT_SECTOR_VERSION_OFFSET) = BE16 (VERSION_NUM);
-
- if (IsOSAtLeast (WIN_VISTA))
- buffer[TC_BOOT_SECTOR_CONFIG_OFFSET] |= TC_BOOT_CFG_FLAG_WINDOWS_VISTA_OR_LATER;
-
- if (rescueDisk && (ReadDriverConfigurationFlags() & TC_DRIVER_CONFIG_DISABLE_HARDWARE_ENCRYPTION))
- buffer[TC_BOOT_SECTOR_CONFIG_OFFSET] |= TC_BOOT_CFG_FLAG_RESCUE_DISABLE_HW_ENCRYPTION;
-
- // Checksum of the backup header of the outer volume for the hidden system
- if (hiddenOSCreation)
- {
- Device device (GetSystemDriveConfiguration().DevicePath);
- device.CheckOpened (SRC_POS);
- byte headerSector[TC_SECTOR_SIZE_BIOS];
-
- device.SeekAt (HiddenOSCandidatePartition.Info.StartingOffset.QuadPart + HiddenOSCandidatePartition.Info.PartitionLength.QuadPart - TC_VOLUME_HEADER_GROUP_SIZE + TC_VOLUME_HEADER_EFFECTIVE_SIZE);
- device.Read (headerSector, sizeof (headerSector));
-
- *(uint32 *) (buffer + TC_BOOT_SECTOR_OUTER_VOLUME_BAK_HEADER_CRC_OFFSET) = GetCrc32 (headerSector, sizeof (headerSector));
- }
-
- // Decompressor
- byte *decompressor = MapResource (L"BIN", IDR_BOOT_LOADER_DECOMPRESSOR, &size);
- if (!decompressor || size > TC_BOOT_LOADER_DECOMPRESSOR_SECTOR_COUNT * TC_SECTOR_SIZE_BIOS)
- throw ParameterIncorrect (SRC_POS);
-
- memcpy (buffer + TC_SECTOR_SIZE_BIOS, decompressor, size);
-
- // Compressed boot loader
- byte *bootLoader = MapResource (L"BIN", bootLoaderId, &size);
- if (!bootLoader || size > TC_MAX_BOOT_LOADER_SECTOR_COUNT * TC_SECTOR_SIZE_BIOS)
- throw ParameterIncorrect (SRC_POS);
-
- memcpy (buffer + TC_SECTOR_SIZE_BIOS + TC_BOOT_LOADER_DECOMPRESSOR_SECTOR_COUNT * TC_SECTOR_SIZE_BIOS, bootLoader, size);
-
- // Boot loader and decompressor checksum
- *(uint16 *) (buffer + TC_BOOT_SECTOR_LOADER_LENGTH_OFFSET) = static_cast <uint16> (size);
- *(uint32 *) (buffer + TC_BOOT_SECTOR_LOADER_CHECKSUM_OFFSET) = GetChecksum (buffer + TC_SECTOR_SIZE_BIOS,
- TC_BOOT_LOADER_DECOMPRESSOR_SECTOR_COUNT * TC_SECTOR_SIZE_BIOS + size);
-
- // Backup of decompressor and boot loader
- if (size + TC_BOOT_LOADER_DECOMPRESSOR_SECTOR_COUNT * TC_SECTOR_SIZE_BIOS <= TC_BOOT_LOADER_BACKUP_SECTOR_COUNT * TC_SECTOR_SIZE_BIOS)
- {
- memcpy (buffer + TC_SECTOR_SIZE_BIOS + TC_BOOT_LOADER_BACKUP_SECTOR_COUNT * TC_SECTOR_SIZE_BIOS,
- buffer + TC_SECTOR_SIZE_BIOS, TC_BOOT_LOADER_BACKUP_SECTOR_COUNT * TC_SECTOR_SIZE_BIOS);
-
- buffer[TC_BOOT_SECTOR_CONFIG_OFFSET] |= TC_BOOT_CFG_FLAG_BACKUP_LOADER_AVAILABLE;
- }
- else if (!rescueDisk && bootLoaderId != IDR_BOOT_LOADER && bootLoaderId != IDR_BOOT_LOADER_SHA2)
- {
- throw ParameterIncorrect (SRC_POS);
- }
- }
-
-
- void BootEncryption::ReadBootSectorConfig (byte *config, size_t bufLength, byte *userConfig, string *customUserMessage, uint16 *bootLoaderVersion)
- {
- if (config && bufLength < TC_BOOT_CFG_FLAG_AREA_SIZE)
- throw ParameterIncorrect (SRC_POS);
-
- GetSystemDriveConfigurationRequest request;
- StringCchCopyW (request.DevicePath, ARRAYSIZE (request.DevicePath), GetSystemDriveConfiguration().DeviceKernelPath.c_str());
-
- try
- {
- CallDriver (TC_IOCTL_GET_SYSTEM_DRIVE_CONFIG, &request, sizeof (request), &request, sizeof (request));
- if (config)
- *config = request.Configuration;
-
- if (userConfig)
- *userConfig = request.UserConfiguration;
-
- if (customUserMessage)
- {
- request.CustomUserMessage[TC_BOOT_SECTOR_USER_MESSAGE_MAX_LENGTH] = 0;
- *customUserMessage = request.CustomUserMessage;
- }
-
- if (bootLoaderVersion)
- *bootLoaderVersion = request.BootLoaderVersion;
- }
- catch (...)
- {
- if (config)
- *config = 0;
-
- if (userConfig)
- *userConfig = 0;
-
- if (customUserMessage)
- customUserMessage->clear();
-
- if (bootLoaderVersion)
- *bootLoaderVersion = 0;
- }
- }
-
-
- void BootEncryption::WriteBootSectorConfig (const byte newConfig[])
- {
- Device device (GetSystemDriveConfiguration().DevicePath);
- device.CheckOpened (SRC_POS);
- byte mbr[TC_SECTOR_SIZE_BIOS];
-
- device.SeekAt (0);
- device.Read (mbr, sizeof (mbr));
-
- memcpy (mbr + TC_BOOT_SECTOR_CONFIG_OFFSET, newConfig, TC_BOOT_CFG_FLAG_AREA_SIZE);
-
- device.SeekAt (0);
- device.Write (mbr, sizeof (mbr));
-
- byte mbrVerificationBuf[TC_SECTOR_SIZE_BIOS];
- device.SeekAt (0);
- device.Read (mbrVerificationBuf, sizeof (mbr));
-
- if (memcmp (mbr, mbrVerificationBuf, sizeof (mbr)) != 0)
- throw ErrorException ("ERROR_MBR_PROTECTED", SRC_POS);
- }
-
-
- void BootEncryption::WriteBootSectorUserConfig (byte userConfig, const string &customUserMessage, int pim)
- {
- Device device (GetSystemDriveConfiguration().DevicePath);
- device.CheckOpened (SRC_POS);
- byte mbr[TC_SECTOR_SIZE_BIOS];
-
- device.SeekAt (0);
- device.Read (mbr, sizeof (mbr));
-
- if (!BufferContainsString (mbr, sizeof (mbr), TC_APP_NAME)
- || BE16 (*(uint16 *) (mbr + TC_BOOT_SECTOR_VERSION_OFFSET)) != VERSION_NUM)
- {
- return;
- }
-
- mbr[TC_BOOT_SECTOR_USER_CONFIG_OFFSET] = userConfig;
-
- memset (mbr + TC_BOOT_SECTOR_USER_MESSAGE_OFFSET, 0, TC_BOOT_SECTOR_USER_MESSAGE_MAX_LENGTH);
-
- if (!customUserMessage.empty())
- {
- if (customUserMessage.size() > TC_BOOT_SECTOR_USER_MESSAGE_MAX_LENGTH)
- throw ParameterIncorrect (SRC_POS);
-
- memcpy (mbr + TC_BOOT_SECTOR_USER_MESSAGE_OFFSET, customUserMessage.c_str(), customUserMessage.size());
- }
-
- if (userConfig & TC_BOOT_USER_CFG_FLAG_DISABLE_PIM)
- {
- // PIM for pre-boot authentication can be encoded on two bytes since its maximum
- // value is 65535 (0xFFFF)
- memcpy (mbr + TC_BOOT_SECTOR_PIM_VALUE_OFFSET, &pim, TC_BOOT_SECTOR_PIM_VALUE_SIZE);
- }
- else
- memset (mbr + TC_BOOT_SECTOR_PIM_VALUE_OFFSET, 0, TC_BOOT_SECTOR_PIM_VALUE_SIZE);
-
- device.SeekAt (0);
- device.Write (mbr, sizeof (mbr));
-
- byte mbrVerificationBuf[TC_SECTOR_SIZE_BIOS];
- device.SeekAt (0);
- device.Read (mbrVerificationBuf, sizeof (mbr));
-
- if (memcmp (mbr, mbrVerificationBuf, sizeof (mbr)) != 0)
- throw ErrorException ("ERROR_MBR_PROTECTED", SRC_POS);
- }
-
-
- unsigned int BootEncryption::GetHiddenOSCreationPhase ()
- {
- byte configFlags [TC_BOOT_CFG_FLAG_AREA_SIZE];
-
- ReadBootSectorConfig (configFlags, sizeof(configFlags));
-
- return (configFlags[0] & TC_BOOT_CFG_MASK_HIDDEN_OS_CREATION_PHASE);
- }
-
-
- void BootEncryption::SetHiddenOSCreationPhase (unsigned int newPhase)
- {
-#if TC_BOOT_CFG_FLAG_AREA_SIZE != 1
-# error TC_BOOT_CFG_FLAG_AREA_SIZE != 1; revise GetHiddenOSCreationPhase() and SetHiddenOSCreationPhase()
-#endif
- byte configFlags [TC_BOOT_CFG_FLAG_AREA_SIZE];
-
- ReadBootSectorConfig (configFlags, sizeof(configFlags));
-
- configFlags[0] &= (byte) ~TC_BOOT_CFG_MASK_HIDDEN_OS_CREATION_PHASE;
-
- configFlags[0] |= newPhase;
-
- WriteBootSectorConfig (configFlags);
- }
-
-
-#ifndef SETUP
-
- void BootEncryption::StartDecoyOSWipe (WipeAlgorithmId wipeAlgorithm)
- {
- if (!IsHiddenOSRunning())
- throw ParameterIncorrect (SRC_POS);
-
- WipeDecoySystemRequest request;
- ZeroMemory (&request, sizeof (request));
-
- request.WipeAlgorithm = wipeAlgorithm;
-
- if (Randinit() != ERR_SUCCESS)
- {
- if (CryptoAPILastError == ERROR_SUCCESS)
- throw RandInitFailed (SRC_POS, GetLastError ());
- else
- throw CryptoApiFailed (SRC_POS, CryptoAPILastError);
- }
-
- /* force the display of the random enriching dialog */
- SetRandomPoolEnrichedByUserStatus (FALSE);
-
- UserEnrichRandomPool (ParentWindow);
-
- if (!RandgetBytes (ParentWindow, request.WipeKey, sizeof (request.WipeKey), TRUE))
- throw ParameterIncorrect (SRC_POS);
-
- CallDriver (TC_IOCTL_START_DECOY_SYSTEM_WIPE, &request, sizeof (request), NULL, 0);
-
- burn (&request, sizeof (request));
- }
-
-
- void BootEncryption::AbortDecoyOSWipe ()
- {
- CallDriver (TC_IOCTL_ABORT_DECOY_SYSTEM_WIPE);
- }
-
-
- DecoySystemWipeStatus BootEncryption::GetDecoyOSWipeStatus ()
- {
- DecoySystemWipeStatus status;
- CallDriver (TC_IOCTL_GET_DECOY_SYSTEM_WIPE_STATUS, NULL, 0, &status, sizeof (status));
- return status;
- }
-
-
- void BootEncryption::CheckDecoyOSWipeResult ()
- {
- CallDriver (TC_IOCTL_GET_DECOY_SYSTEM_WIPE_RESULT);
- }
-
-
- void BootEncryption::WipeHiddenOSCreationConfig ()
- {
- if (IsHiddenOSRunning())
- throw ParameterIncorrect (SRC_POS);
-
- if (Randinit() != ERR_SUCCESS)
- {
- if (CryptoAPILastError == ERROR_SUCCESS)
- throw RandInitFailed (SRC_POS, GetLastError ());
- else
- throw CryptoApiFailed (SRC_POS, CryptoAPILastError);
- }
-
- Device device (GetSystemDriveConfiguration().DevicePath);
- device.CheckOpened(SRC_POS);
- byte mbr[TC_SECTOR_SIZE_BIOS];
-
- device.SeekAt (0);
- device.Read (mbr, sizeof (mbr));
-
- finally_do_arg (BootEncryption *, this,
- {
- try
- {
- finally_arg->SetHiddenOSCreationPhase (TC_HIDDEN_OS_CREATION_PHASE_NONE);
- } catch (...) { }
- });
-
-#if PRAND_DISK_WIPE_PASSES > RNG_POOL_SIZE
-# error PRAND_DISK_WIPE_PASSES > RNG_POOL_SIZE
-#endif
-
- byte randData[PRAND_DISK_WIPE_PASSES];
- if (!RandgetBytes (ParentWindow, randData, sizeof (randData), FALSE))
- throw ParameterIncorrect (SRC_POS);
-
- for (int wipePass = 0; wipePass < PRAND_DISK_WIPE_PASSES; wipePass++)
- {
- for (int i = 0; i < TC_BOOT_SECTOR_OUTER_VOLUME_BAK_HEADER_CRC_SIZE; ++i)
- {
- mbr[TC_BOOT_SECTOR_OUTER_VOLUME_BAK_HEADER_CRC_OFFSET + i] = randData[wipePass];
- }
-
- mbr[TC_BOOT_SECTOR_CONFIG_OFFSET] &= (byte) ~TC_BOOT_CFG_MASK_HIDDEN_OS_CREATION_PHASE;
- mbr[TC_BOOT_SECTOR_CONFIG_OFFSET] |= randData[wipePass] & TC_BOOT_CFG_MASK_HIDDEN_OS_CREATION_PHASE;
-
- if (wipePass == PRAND_DISK_WIPE_PASSES - 1)
- memset (mbr + TC_BOOT_SECTOR_OUTER_VOLUME_BAK_HEADER_CRC_OFFSET, 0, TC_BOOT_SECTOR_OUTER_VOLUME_BAK_HEADER_CRC_SIZE);
-
- device.SeekAt (0);
- device.Write (mbr, sizeof (mbr));
- }
-
- for (int wipePass = 0; wipePass < PRAND_DISK_WIPE_PASSES/4 + 1; wipePass++)
- {
- SetHiddenOSCreationPhase (TC_HIDDEN_OS_CREATION_PHASE_NONE);
- SetHiddenOSCreationPhase (TC_HIDDEN_OS_CREATION_PHASE_CLONING);
- SetHiddenOSCreationPhase (TC_HIDDEN_OS_CREATION_PHASE_WIPING);
- SetHiddenOSCreationPhase (TC_HIDDEN_OS_CREATION_PHASE_WIPED);
- }
- SetHiddenOSCreationPhase (TC_HIDDEN_OS_CREATION_PHASE_NONE);
- }
-
-#endif // !SETUP
-
-
- void BootEncryption::InstallBootLoader (bool preserveUserConfig, bool hiddenOSCreation)
- {
- Device device (GetSystemDriveConfiguration().DevicePath);
- device.CheckOpened (SRC_POS);
-
- InstallBootLoader (device, preserveUserConfig, hiddenOSCreation);
- }
-
- void BootEncryption::InstallBootLoader (Device& device, bool preserveUserConfig, bool hiddenOSCreation, int pim)
- {
- byte bootLoaderBuf[TC_BOOT_LOADER_AREA_SIZE - TC_BOOT_ENCRYPTION_VOLUME_HEADER_SIZE] = {0};
- CreateBootLoaderInMemory (bootLoaderBuf, sizeof (bootLoaderBuf), false, hiddenOSCreation);
-
- // Write MBR
- byte mbr[TC_SECTOR_SIZE_BIOS];
-
- device.SeekAt (0);
- device.Read (mbr, sizeof (mbr));
-
- if (preserveUserConfig && BufferContainsString (mbr, sizeof (mbr), TC_APP_NAME))
- {
- uint16 version = BE16 (*(uint16 *) (mbr + TC_BOOT_SECTOR_VERSION_OFFSET));
- if (version != 0)
- {
- bootLoaderBuf[TC_BOOT_SECTOR_USER_CONFIG_OFFSET] = mbr[TC_BOOT_SECTOR_USER_CONFIG_OFFSET];
- memcpy (bootLoaderBuf + TC_BOOT_SECTOR_USER_MESSAGE_OFFSET, mbr + TC_BOOT_SECTOR_USER_MESSAGE_OFFSET, TC_BOOT_SECTOR_USER_MESSAGE_MAX_LENGTH);
-
- if (bootLoaderBuf[TC_BOOT_SECTOR_USER_CONFIG_OFFSET] & TC_BOOT_USER_CFG_FLAG_DISABLE_PIM)
- {
- if (pim >= 0)
- {
- memcpy (bootLoaderBuf + TC_BOOT_SECTOR_PIM_VALUE_OFFSET, &pim, TC_BOOT_SECTOR_PIM_VALUE_SIZE);
- }
- else
- memcpy (bootLoaderBuf + TC_BOOT_SECTOR_PIM_VALUE_OFFSET, mbr + TC_BOOT_SECTOR_PIM_VALUE_OFFSET, TC_BOOT_SECTOR_PIM_VALUE_SIZE);
- }
- }
- }
-
- memcpy (mbr, bootLoaderBuf, TC_MAX_MBR_BOOT_CODE_SIZE);
-
- device.SeekAt (0);
- device.Write (mbr, sizeof (mbr));
-
- byte mbrVerificationBuf[TC_SECTOR_SIZE_BIOS];
- device.SeekAt (0);
- device.Read (mbrVerificationBuf, sizeof (mbr));
-
- if (memcmp (mbr, mbrVerificationBuf, sizeof (mbr)) != 0)
- throw ErrorException ("ERROR_MBR_PROTECTED", SRC_POS);
-
- // Write boot loader
- device.SeekAt (TC_SECTOR_SIZE_BIOS);
- device.Write (bootLoaderBuf + TC_SECTOR_SIZE_BIOS, sizeof (bootLoaderBuf) - TC_SECTOR_SIZE_BIOS);
- }
-
-#ifndef SETUP
- bool BootEncryption::CheckBootloaderFingerprint (bool bSilent)
- {
- byte bootLoaderBuf[TC_BOOT_LOADER_AREA_SIZE - TC_BOOT_ENCRYPTION_VOLUME_HEADER_SIZE] = {0};
- byte fingerprint[WHIRLPOOL_DIGESTSIZE + SHA512_DIGESTSIZE];
- byte expectedFingerprint[WHIRLPOOL_DIGESTSIZE + SHA512_DIGESTSIZE];
- bool bRet = false;
-
- try
- {
- // read bootloader fingerprint
- GetInstalledBootLoaderFingerprint (fingerprint);
-
- // compute expected fingerprint
- CreateBootLoaderInMemory (bootLoaderBuf, sizeof (bootLoaderBuf), false, false);
- ::ComputeBootloaderFingerprint (bootLoaderBuf, sizeof (bootLoaderBuf), expectedFingerprint);
-
- // compare values
- if (0 == memcmp (fingerprint, expectedFingerprint, sizeof (expectedFingerprint)))
- {
- bRet = true;
- }
- }
- catch (SystemException &e)
- {
- if (!bSilent && (GetLastError () != ERROR_INVALID_IMAGE_HASH))
- e.Show (ParentWindow);
- }
- catch (Exception& e)
- {
- if (!bSilent)
- e.Show (ParentWindow);
- }
-
- return bRet;
- }
-#endif
-
- wstring BootEncryption::GetSystemLoaderBackupPath ()
- {
- WCHAR pathBuf[MAX_PATH];
-
- throw_sys_if (!SUCCEEDED (SHGetFolderPath (NULL, CSIDL_COMMON_APPDATA | CSIDL_FLAG_CREATE, NULL, 0, pathBuf)));
-
- wstring path = wstring (pathBuf) + L"\\" _T(TC_APP_NAME);
- CreateDirectory (path.c_str(), NULL);
-
- return path + L'\\' + TC_SYS_BOOT_LOADER_BACKUP_NAME;
- }
-
-
- void BootEncryption::RenameDeprecatedSystemLoaderBackup ()
- {
- WCHAR pathBuf[MAX_PATH];
-
- if (SUCCEEDED (SHGetFolderPath (NULL, CSIDL_COMMON_APPDATA, NULL, 0, pathBuf)))
- {
- wstring path = wstring (pathBuf) + L"\\" _T(TC_APP_NAME) + L'\\' + TC_SYS_BOOT_LOADER_BACKUP_NAME_LEGACY;
-
- if (FileExists (path.c_str()) && !FileExists (GetSystemLoaderBackupPath().c_str()))
- throw_sys_if (_wrename (path.c_str(), GetSystemLoaderBackupPath().c_str()) != 0);
- }
- }
-
-
-#ifndef SETUP
- void BootEncryption::CreateRescueIsoImage (bool initialSetup, const wstring &isoImagePath)
- {
- BootEncryptionStatus encStatus = GetStatus();
- if (encStatus.SetupInProgress)
- throw ParameterIncorrect (SRC_POS);
-
- Buffer imageBuf (RescueIsoImageSize);
-
- byte *image = imageBuf.Ptr();
- memset (image, 0, RescueIsoImageSize);
-
- // Primary volume descriptor
- const char* szPrimVolDesc = "\001CD001\001";
- const char* szPrimVolLabel = "VeraCrypt Rescue Disk ";
- memcpy (image + 0x8000, szPrimVolDesc, strlen(szPrimVolDesc) + 1);
- memcpy (image + 0x7fff + 41, szPrimVolLabel, strlen(szPrimVolLabel) + 1);
- *(uint32 *) (image + 0x7fff + 81) = RescueIsoImageSize / 2048;
- *(uint32 *) (image + 0x7fff + 85) = BE32 (RescueIsoImageSize / 2048);
- image[0x7fff + 121] = 1;
- image[0x7fff + 124] = 1;
- image[0x7fff + 125] = 1;
- image[0x7fff + 128] = 1;
- image[0x7fff + 130] = 8;
- image[0x7fff + 131] = 8;
-
- image[0x7fff + 133] = 10;
- image[0x7fff + 140] = 10;
- image[0x7fff + 141] = 0x14;
- image[0x7fff + 157] = 0x22;
- image[0x7fff + 159] = 0x18;
-
- // Boot record volume descriptor
- const char* szBootRecDesc = "CD001\001EL TORITO SPECIFICATION";
- memcpy (image + 0x8801, szBootRecDesc, strlen(szBootRecDesc) + 1);
- image[0x8800 + 0x47] = 0x19;
-
- // Volume descriptor set terminator
- const char* szVolDescTerm = "\377CD001\001";
- memcpy (image + 0x9000, szVolDescTerm, strlen(szVolDescTerm) + 1);
-
- // Path table
- image[0xA000 + 0] = 1;
- image[0xA000 + 2] = 0x18;
- image[0xA000 + 6] = 1;
-
- // Root directory
- image[0xc000 + 0] = 0x22;
- image[0xc000 + 2] = 0x18;
- image[0xc000 + 9] = 0x18;
- image[0xc000 + 11] = 0x08;
- image[0xc000 + 16] = 0x08;
- image[0xc000 + 25] = 0x02;
- image[0xc000 + 28] = 0x01;
- image[0xc000 + 31] = 0x01;
- image[0xc000 + 32] = 0x01;
- image[0xc000 + 34] = 0x22;
- image[0xc000 + 36] = 0x18;
- image[0xc000 + 43] = 0x18;
- image[0xc000 + 45] = 0x08;
- image[0xc000 + 50] = 0x08;
- image[0xc000 + 59] = 0x02;
- image[0xc000 + 62] = 0x01;
- *(uint32 *) (image + 0xc000 + 65) = 0x010101;
-
- // Validation entry
- image[0xc800] = 1;
- int offset = 0xc800 + 0x1c;
- image[offset++] = 0xaa;
- image[offset++] = 0x55;
- image[offset++] = 0x55;
- image[offset] = 0xaa;
-
- // Initial entry
- offset = 0xc820;
- image[offset++] = 0x88;
- image[offset++] = 2;
- image[0xc820 + 6] = 1;
- image[0xc820 + 8] = TC_CD_BOOT_LOADER_SECTOR;
-
- // TrueCrypt Boot Loader
- CreateBootLoaderInMemory (image + TC_CD_BOOTSECTOR_OFFSET, TC_BOOT_LOADER_AREA_SIZE, true);
-
- // Volume header
- if (initialSetup)
- {
- if (!RescueVolumeHeaderValid)
- throw ParameterIncorrect (SRC_POS);
-
- memcpy (image + TC_CD_BOOTSECTOR_OFFSET + TC_BOOT_VOLUME_HEADER_SECTOR_OFFSET, RescueVolumeHeader, TC_BOOT_ENCRYPTION_VOLUME_HEADER_SIZE);
- }
- else
- {
- Device bootDevice (GetSystemDriveConfiguration().DevicePath, true);
- bootDevice.CheckOpened (SRC_POS);
- bootDevice.SeekAt (TC_BOOT_VOLUME_HEADER_SECTOR_OFFSET);
- bootDevice.Read (image + TC_CD_BOOTSECTOR_OFFSET + TC_BOOT_VOLUME_HEADER_SECTOR_OFFSET, TC_BOOT_ENCRYPTION_VOLUME_HEADER_SIZE);
- }
-
- // Original system loader
- try
- {
- File sysBakFile (GetSystemLoaderBackupPath(), true);
- sysBakFile.CheckOpened (SRC_POS);
- sysBakFile.Read (image + TC_CD_BOOTSECTOR_OFFSET + TC_ORIG_BOOT_LOADER_BACKUP_SECTOR_OFFSET, TC_BOOT_LOADER_AREA_SIZE);
-
- image[TC_CD_BOOTSECTOR_OFFSET + TC_BOOT_SECTOR_CONFIG_OFFSET] |= TC_BOOT_CFG_FLAG_RESCUE_DISK_ORIG_SYS_LOADER;
- }
- catch (Exception &e)
- {
- e.Show (ParentWindow);
- Warning ("SYS_LOADER_UNAVAILABLE_FOR_RESCUE_DISK", ParentWindow);
- }
-
- // Boot loader backup
- CreateBootLoaderInMemory (image + TC_CD_BOOTSECTOR_OFFSET + TC_BOOT_LOADER_BACKUP_RESCUE_DISK_SECTOR_OFFSET, TC_BOOT_LOADER_AREA_SIZE, false);
-
- RescueIsoImage = new byte[RescueIsoImageSize];
- if (!RescueIsoImage)
- throw bad_alloc();
- memcpy (RescueIsoImage, image, RescueIsoImageSize);
-
- if (!isoImagePath.empty())
- {
- File isoFile (isoImagePath, false, true);
- isoFile.Write (image, RescueIsoImageSize);
- }
- }
-#endif
-
-
- bool BootEncryption::IsCDRecorderPresent ()
- {
- ICDBurn* pICDBurn;
- BOOL bHasRecorder = FALSE;
-
- if (SUCCEEDED( CoCreateInstance (CLSID_CDBurn, NULL,CLSCTX_INPROC_SERVER,IID_ICDBurn,(LPVOID*)&pICDBurn)))
- {
- if (pICDBurn->HasRecordableDrive (&bHasRecorder) != S_OK)
- {
- bHasRecorder = FALSE;
- }
- pICDBurn->Release();
- }
- return bHasRecorder? true : false;
- }
-
-
- bool BootEncryption::VerifyRescueDisk ()
- {
- if (!RescueIsoImage)
- throw ParameterIncorrect (SRC_POS);
-
- for (WCHAR drive = L'Z'; drive >= L'C'; --drive)
- {
- try
- {
- WCHAR rootPath[4] = { drive, L':', L'\\', 0};
- UINT driveType = GetDriveType (rootPath);
- // check that it is a CD/DVD drive or a removable media in case a bootable
- // USB key was created from the rescue disk ISO file
- if ((DRIVE_CDROM == driveType) || (DRIVE_REMOVABLE == driveType))
- {
- rootPath[2] = 0; // remove trailing backslash
-
- Device driveDevice (rootPath, true);
- driveDevice.CheckOpened (SRC_POS);
- size_t verifiedSectorCount = (TC_CD_BOOTSECTOR_OFFSET + TC_ORIG_BOOT_LOADER_BACKUP_SECTOR_OFFSET + TC_BOOT_LOADER_AREA_SIZE) / 2048;
- Buffer buffer ((verifiedSectorCount + 1) * 2048);
-
- DWORD bytesRead = driveDevice.Read (buffer.Ptr(), (DWORD) buffer.Size());
- if (bytesRead != buffer.Size())
- continue;
-
- if (memcmp (buffer.Ptr(), RescueIsoImage, buffer.Size()) == 0)
- return true;
- }
- }
- catch (...) { }
- }
-
- return false;
- }
-
- bool BootEncryption::VerifyRescueDiskIsoImage (const wchar_t* imageFile)
- {
- if (!RescueIsoImage)
- throw ParameterIncorrect (SRC_POS);
-
- try
- {
- File isoFile (imageFile, true);
- isoFile.CheckOpened (SRC_POS);
- size_t verifiedSectorCount = (TC_CD_BOOTSECTOR_OFFSET + TC_ORIG_BOOT_LOADER_BACKUP_SECTOR_OFFSET + TC_BOOT_LOADER_AREA_SIZE) / 2048;
- Buffer buffer ((verifiedSectorCount + 1) * 2048);
-
- DWORD bytesRead = isoFile.Read (buffer.Ptr(), (DWORD) buffer.Size());
- if ( (bytesRead == buffer.Size())
- && (memcmp (buffer.Ptr(), RescueIsoImage, buffer.Size()) == 0)
- )
- {
- return true;
- }
- }
- catch (...) { }
-
- return false;
- }
-
-
-#ifndef SETUP
-
- void BootEncryption::CreateVolumeHeader (uint64 volumeSize, uint64 encryptedAreaStart, Password *password, int ea, int mode, int pkcs5, int pim)
- {
- PCRYPTO_INFO cryptoInfo = NULL;
-
- if (!IsRandomNumberGeneratorStarted())
- throw ParameterIncorrect (SRC_POS);
-
- throw_sys_if (CreateVolumeHeaderInMemory (ParentWindow, TRUE, (char *) VolumeHeader, ea, mode, password, pkcs5, pim, NULL, &cryptoInfo,
- volumeSize, 0, encryptedAreaStart, 0, TC_SYSENC_KEYSCOPE_MIN_REQ_PROG_VERSION, TC_HEADER_FLAG_ENCRYPTED_SYSTEM, TC_SECTOR_SIZE_BIOS, FALSE) != 0);
-
- finally_do_arg (PCRYPTO_INFO*, &cryptoInfo, { crypto_close (*finally_arg); });
-
- // Initial rescue disk assumes encryption of the drive has been completed (EncryptedAreaLength == volumeSize)
- memcpy (RescueVolumeHeader, VolumeHeader, sizeof (RescueVolumeHeader));
- if (0 != ReadVolumeHeader (TRUE, (char *) RescueVolumeHeader, password, pkcs5, pim, FALSE, NULL, cryptoInfo))
- throw ParameterIncorrect (SRC_POS);
-
- DecryptBuffer (RescueVolumeHeader + HEADER_ENCRYPTED_DATA_OFFSET, HEADER_ENCRYPTED_DATA_SIZE, cryptoInfo);
-
- if (GetHeaderField32 (RescueVolumeHeader, TC_HEADER_OFFSET_MAGIC) != 0x56455241)
- throw ParameterIncorrect (SRC_POS);
-
- byte *fieldPos = RescueVolumeHeader + TC_HEADER_OFFSET_ENCRYPTED_AREA_LENGTH;
- mputInt64 (fieldPos, volumeSize);
-
- // CRC of the header fields
- uint32 crc = GetCrc32 (RescueVolumeHeader + TC_HEADER_OFFSET_MAGIC, TC_HEADER_OFFSET_HEADER_CRC - TC_HEADER_OFFSET_MAGIC);
- fieldPos = RescueVolumeHeader + TC_HEADER_OFFSET_HEADER_CRC;
- mputLong (fieldPos, crc);
-
- EncryptBuffer (RescueVolumeHeader + HEADER_ENCRYPTED_DATA_OFFSET, HEADER_ENCRYPTED_DATA_SIZE, cryptoInfo);
-
- VolumeHeaderValid = true;
- RescueVolumeHeaderValid = true;
- }
-
-
- void BootEncryption::InstallVolumeHeader ()
- {
- if (!VolumeHeaderValid)
- throw ParameterIncorrect (SRC_POS);
-
- Device device (GetSystemDriveConfiguration().DevicePath);
- device.CheckOpened (SRC_POS);
-
- device.SeekAt (TC_BOOT_VOLUME_HEADER_SECTOR_OFFSET);
- device.Write ((byte *) VolumeHeader, sizeof (VolumeHeader));
- }
-
-
- // For synchronous operations use AbortSetupWait()
- void BootEncryption::AbortSetup ()
- {
- CallDriver (TC_IOCTL_ABORT_BOOT_ENCRYPTION_SETUP);
- }
-
-
- // For asynchronous operations use AbortSetup()
- void BootEncryption::AbortSetupWait ()
- {
- CallDriver (TC_IOCTL_ABORT_BOOT_ENCRYPTION_SETUP);
-
- BootEncryptionStatus encStatus = GetStatus();
-
- while (encStatus.SetupInProgress)
- {
- Sleep (TC_ABORT_TRANSFORM_WAIT_INTERVAL);
- encStatus = GetStatus();
- }
- }
-
-
- void BootEncryption::BackupSystemLoader ()
- {
- Device device (GetSystemDriveConfiguration().DevicePath, true);
- device.CheckOpened (SRC_POS);
- byte bootLoaderBuf[TC_BOOT_LOADER_AREA_SECTOR_COUNT * TC_SECTOR_SIZE_BIOS];
-
- device.SeekAt (0);
- device.Read (bootLoaderBuf, sizeof (bootLoaderBuf));
-
- // Prevent TrueCrypt loader from being backed up
- for (size_t i = 0; i < sizeof (bootLoaderBuf) - strlen (TC_APP_NAME); ++i)
- {
- if (memcmp (bootLoaderBuf + i, TC_APP_NAME, strlen (TC_APP_NAME)) == 0)
- {
- if (AskWarnNoYes ("TC_BOOT_LOADER_ALREADY_INSTALLED", ParentWindow) == IDNO)
- throw UserAbort (SRC_POS);
- return;
- }
- }
-
- File backupFile (GetSystemLoaderBackupPath(), false, true);
- backupFile.Write (bootLoaderBuf, sizeof (bootLoaderBuf));
- }
-
-
- void BootEncryption::RestoreSystemLoader ()
- {
- byte bootLoaderBuf[TC_BOOT_LOADER_AREA_SECTOR_COUNT * TC_SECTOR_SIZE_BIOS];
-
- File backupFile (GetSystemLoaderBackupPath(), true);
- backupFile.CheckOpened(SRC_POS);
- if (backupFile.Read (bootLoaderBuf, sizeof (bootLoaderBuf)) != sizeof (bootLoaderBuf))
- throw ParameterIncorrect (SRC_POS);
-
- Device device (GetSystemDriveConfiguration().DevicePath);
- device.CheckOpened (SRC_POS);
-
- // Preserve current partition table
- byte mbr[TC_SECTOR_SIZE_BIOS];
- device.SeekAt (0);
- device.Read (mbr, sizeof (mbr));
- memcpy (bootLoaderBuf + TC_MAX_MBR_BOOT_CODE_SIZE, mbr + TC_MAX_MBR_BOOT_CODE_SIZE, sizeof (mbr) - TC_MAX_MBR_BOOT_CODE_SIZE);
-
- device.SeekAt (0);
- device.Write (bootLoaderBuf, sizeof (bootLoaderBuf));
- }
-
-#endif // SETUP
-
- void BootEncryption::RegisterFilter (bool registerFilter, FilterType filterType, const GUID *deviceClassGuid)
- {
- string filter;
- string filterReg;
- HKEY regKey;
-
- switch (filterType)
- {
- case DriveFilter:
- case VolumeFilter:
- filter = "veracrypt";
- filterReg = "UpperFilters";
- regKey = OpenDeviceClassRegKey (deviceClassGuid);
- throw_sys_if (regKey == INVALID_HANDLE_VALUE);
-
- break;
-
- case DumpFilter:
- if (!IsOSAtLeast (WIN_VISTA))
- return;
-
- filter = "veracrypt.sys";
- filterReg = "DumpFilters";
- SetLastError (RegOpenKeyEx (HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Control\\CrashControl", 0, KEY_READ | KEY_WRITE, ®Key));
- throw_sys_if (GetLastError() != ERROR_SUCCESS);
-
- break;
-
- default:
- throw ParameterIncorrect (SRC_POS);
- }
-
- finally_do_arg (HKEY, regKey, { RegCloseKey (finally_arg); });
-
- if (registerFilter && filterType != DumpFilter)
- {
- // Register class filter below all other filters in the stack
-
- size_t strSize = filter.size() + 1;
- byte regKeyBuf[65536];
- DWORD size = (DWORD) (sizeof (regKeyBuf) - strSize);
-
- // SetupInstallFromInfSection() does not support prepending of values so we have to modify the registry directly
- StringCchCopyA ((char *) regKeyBuf, ARRAYSIZE(regKeyBuf), filter.c_str());
-
- if (RegQueryValueExA (regKey, filterReg.c_str(), NULL, NULL, regKeyBuf + strSize, &size) != ERROR_SUCCESS)
- size = 1;
-
- SetLastError (RegSetValueExA (regKey, filterReg.c_str(), 0, REG_MULTI_SZ, regKeyBuf, (DWORD) strSize + size));
- throw_sys_if (GetLastError() != ERROR_SUCCESS);
- }
- else
- {
- RegisterDriverInf (registerFilter, filter, filterReg, ParentWindow, regKey);
- }
- }
-
- void BootEncryption::RegisterFilterDriver (bool registerDriver, FilterType filterType)
- {
- if (!IsAdmin() && IsUacSupported())
- {
- Elevator::RegisterFilterDriver (registerDriver, filterType);
- return;
- }
-
- switch (filterType)
- {
- case DriveFilter:
- RegisterFilter (registerDriver, filterType, &GUID_DEVCLASS_DISKDRIVE);
- break;
-
- case VolumeFilter:
- RegisterFilter (registerDriver, filterType, &GUID_DEVCLASS_VOLUME);
- RegisterFilter (registerDriver, filterType, &GUID_DEVCLASS_FLOPPYDISK);
- break;
-
- case DumpFilter:
- RegisterFilter (registerDriver, filterType);
- break;
-
- default:
- throw ParameterIncorrect (SRC_POS);
- }
- }
-
- void BootEncryption::RegisterSystemFavoritesService (BOOL registerService, BOOL noFileHandling)
- {
- SC_HANDLE scm = OpenSCManager (NULL, NULL, SC_MANAGER_ALL_ACCESS);
- throw_sys_if (!scm);
- finally_do_arg (SC_HANDLE, scm, { CloseServiceHandle (finally_arg); });
-
- wstring servicePath = GetServiceConfigPath (_T(TC_APP_NAME) L".exe", false);
- wstring serviceLegacyPath = GetServiceConfigPath (_T(TC_APP_NAME) L".exe", true);
-
- if (registerService)
- {
- try
- {
- RegisterSystemFavoritesService (FALSE, noFileHandling);
- }
- catch (...) { }
-
- if (!noFileHandling)
- {
- wchar_t appPath[TC_MAX_PATH];
- throw_sys_if (!GetModuleFileName (NULL, appPath, ARRAYSIZE (appPath)));
-
- throw_sys_if (!CopyFile (appPath, servicePath.c_str(), FALSE));
- }
-
- SC_HANDLE service = CreateService (scm,
- TC_SYSTEM_FAVORITES_SERVICE_NAME,
- _T(TC_APP_NAME) L" System Favorites",
- SERVICE_ALL_ACCESS,
- SERVICE_WIN32_OWN_PROCESS,
- SERVICE_AUTO_START,
- SERVICE_ERROR_NORMAL,
- (wstring (L"\"") + servicePath + L"\" " TC_SYSTEM_FAVORITES_SERVICE_CMDLINE_OPTION).c_str(),
- TC_SYSTEM_FAVORITES_SERVICE_LOAD_ORDER_GROUP,
- NULL,
- NULL,
- NULL,
- NULL);
-
- throw_sys_if (!service);
-
- SERVICE_DESCRIPTION description;
- description.lpDescription = L"Mounts VeraCrypt system favorite volumes.";
- ChangeServiceConfig2 (service, SERVICE_CONFIG_DESCRIPTION, &description);
-
- CloseServiceHandle (service);
-
- try
- {
- WriteLocalMachineRegistryString (L"SYSTEM\\CurrentControlSet\\Control\\SafeBoot\\Minimal\\" TC_SYSTEM_FAVORITES_SERVICE_NAME, NULL, L"Service", FALSE);
- WriteLocalMachineRegistryString (L"SYSTEM\\CurrentControlSet\\Control\\SafeBoot\\Network\\" TC_SYSTEM_FAVORITES_SERVICE_NAME, NULL, L"Service", FALSE);
-
- SetDriverConfigurationFlag (TC_DRIVER_CONFIG_CACHE_BOOT_PASSWORD_FOR_SYS_FAVORITES, true);
- }
- catch (...)
- {
- try
- {
- RegisterSystemFavoritesService (FALSE, noFileHandling);
- }
- catch (...) { }
-
- throw;
- }
- }
- else
- {
- SetDriverConfigurationFlag (TC_DRIVER_CONFIG_CACHE_BOOT_PASSWORD_FOR_SYS_FAVORITES, false);
-
- DeleteLocalMachineRegistryKey (L"SYSTEM\\CurrentControlSet\\Control\\SafeBoot\\Minimal", TC_SYSTEM_FAVORITES_SERVICE_NAME);
- DeleteLocalMachineRegistryKey (L"SYSTEM\\CurrentControlSet\\Control\\SafeBoot\\Network", TC_SYSTEM_FAVORITES_SERVICE_NAME);
-
- SC_HANDLE service = OpenService (scm, TC_SYSTEM_FAVORITES_SERVICE_NAME, SERVICE_ALL_ACCESS);
- throw_sys_if (!service);
-
- throw_sys_if (!DeleteService (service));
- CloseServiceHandle (service);
-
- if (!noFileHandling)
- {
- DeleteFile (servicePath.c_str());
- if (serviceLegacyPath != servicePath)
- DeleteFile (serviceLegacyPath.c_str());
- }
- }
- }
-
- void BootEncryption::UpdateSystemFavoritesService ()
- {
- SC_HANDLE scm = OpenSCManager (NULL, NULL, SC_MANAGER_ALL_ACCESS);
- throw_sys_if (!scm);
-
- finally_do_arg (SC_HANDLE, scm, { CloseServiceHandle (finally_arg); });
-
- wstring servicePath = GetServiceConfigPath (_T(TC_APP_NAME) L".exe", false);
-
- // check if service exists
- SC_HANDLE service = OpenService (scm, TC_SYSTEM_FAVORITES_SERVICE_NAME, SERVICE_ALL_ACCESS);
- if (service)
- {
- finally_do_arg (SC_HANDLE, service, { CloseServiceHandle (finally_arg); });
- // ensure that its parameters are correct
- throw_sys_if (!ChangeServiceConfig (service,
- SERVICE_WIN32_OWN_PROCESS,
- SERVICE_AUTO_START,
- SERVICE_ERROR_NORMAL,
- (wstring (L"\"") + servicePath + L"\" " TC_SYSTEM_FAVORITES_SERVICE_CMDLINE_OPTION).c_str(),
- TC_SYSTEM_FAVORITES_SERVICE_LOAD_ORDER_GROUP,
- NULL,
- NULL,
- NULL,
- NULL,
- _T(TC_APP_NAME) L" System Favorites"));
-
- }
- else
- {
- RegisterSystemFavoritesService (TRUE, TRUE);
- }
- }
-
- void BootEncryption::SetDriverConfigurationFlag (uint32 flag, bool state)
- {
- DWORD configMap = ReadDriverConfigurationFlags();
-
- if (state)
- configMap |= flag;
- else
- configMap &= ~flag;
-#ifdef SETUP
- WriteLocalMachineRegistryDword (L"SYSTEM\\CurrentControlSet\\Services\\veracrypt", TC_DRIVER_CONFIG_REG_VALUE_NAME, configMap);
-#else
- WriteLocalMachineRegistryDwordValue (L"SYSTEM\\CurrentControlSet\\Services\\veracrypt", TC_DRIVER_CONFIG_REG_VALUE_NAME, configMap);
-#endif
- }
-
-#ifndef SETUP
-
- void BootEncryption::RegisterSystemFavoritesService (BOOL registerService)
- {
- if (!IsAdmin() && IsUacSupported())
- {
- Elevator::RegisterSystemFavoritesService (registerService);
- return;
- }
-
- RegisterSystemFavoritesService (registerService, FALSE);
- }
-
- void BootEncryption::CheckRequirements ()
- {
- if (nCurrentOS == WIN_2000)
- throw ErrorException ("SYS_ENCRYPTION_UNSUPPORTED_ON_CURRENT_OS", SRC_POS);
-
- if (CurrentOSMajor == 6 && CurrentOSMinor == 0 && CurrentOSServicePack < 1)
- throw ErrorException ("SYS_ENCRYPTION_UNSUPPORTED_ON_VISTA_SP0", SRC_POS);
-
- if (IsNonInstallMode())
- throw ErrorException ("FEATURE_REQUIRES_INSTALLATION", SRC_POS);
-
- SystemDriveConfiguration config = GetSystemDriveConfiguration ();
-
- if (config.SystemPartition.IsGPT)
- throw ErrorException ("GPT_BOOT_DRIVE_UNSUPPORTED", SRC_POS);
-
- if (SystemDriveIsDynamic())
- throw ErrorException ("SYSENC_UNSUPPORTED_FOR_DYNAMIC_DISK", SRC_POS);
-
- if (config.InitialUnallocatedSpace < TC_BOOT_LOADER_AREA_SIZE)
- throw ErrorException ("NO_SPACE_FOR_BOOT_LOADER", SRC_POS);
-
- DISK_GEOMETRY geometry = GetDriveGeometry (config.DriveNumber);
-
- if (geometry.BytesPerSector != TC_SECTOR_SIZE_BIOS)
- throw ErrorException ("SYSENC_UNSUPPORTED_SECTOR_SIZE_BIOS", SRC_POS);
-
- bool activePartitionFound = false;
- if (!config.SystemPartition.IsGPT)
- {
- // Determine whether there is an Active partition on the system drive
- foreach (const Partition &partition, config.Partitions)
- {
- if (partition.Info.BootIndicator)
- {
- activePartitionFound = true;
- break;
- }
- }
- }
-
- if (!config.SystemLoaderPresent || !activePartitionFound)
- {
- static bool confirmed = false;
-
- if (!confirmed && AskWarnNoYes ("WINDOWS_NOT_ON_BOOT_DRIVE_ERROR", ParentWindow) == IDNO)
- throw UserAbort (SRC_POS);
-
- confirmed = true;
- }
- }
-
-
- void BootEncryption::CheckRequirementsHiddenOS ()
- {
- // It is assumed that CheckRequirements() had been called (so we don't check e.g. whether it's GPT).
-
- // The user may have modified/added/deleted partitions since the partition table was last scanned.
- InvalidateCachedSysDriveProperties ();
-
- GetPartitionForHiddenOS ();
- }
-
-
- void BootEncryption::InitialSecurityChecksForHiddenOS ()
- {
- wchar_t windowsDrive = (wchar_t) towupper (GetWindowsDirectory()[0]);
-
- // Paging files
- bool pagingFilesOk = !IsPagingFileActive (TRUE);
-
- wchar_t pagingFileRegData[65536];
- DWORD pagingFileRegDataSize = sizeof (pagingFileRegData);
-
- if (ReadLocalMachineRegistryMultiString (L"System\\CurrentControlSet\\Control\\Session Manager\\Memory Management", L"PagingFiles", pagingFileRegData, &pagingFileRegDataSize)
- && pagingFileRegDataSize > 8)
- {
- for (size_t i = 1; i < pagingFileRegDataSize/2 - 2; ++i)
- {
- if (wmemcmp (pagingFileRegData + i, L":\\", 2) == 0 && towupper (pagingFileRegData[i - 1]) != windowsDrive)
- {
- pagingFilesOk = false;
- break;
- }
- }
- }
-
- if (!pagingFilesOk)
- {
- if (AskWarnYesNoString ((wchar_t *) (wstring (GetString ("PAGING_FILE_NOT_ON_SYS_PARTITION"))
- + GetString ("LEAKS_OUTSIDE_SYSPART_UNIVERSAL_EXPLANATION")
- + L"\n\n\n"
- + GetString ("RESTRICT_PAGING_FILES_TO_SYS_PARTITION")
- ).c_str(), ParentWindow) == IDYES)
- {
- RestrictPagingFilesToSystemPartition();
- RestartComputer();
- AbortProcessSilent();
- }
-
- throw ErrorException (wstring (GetString ("PAGING_FILE_NOT_ON_SYS_PARTITION"))
- + GetString ("LEAKS_OUTSIDE_SYSPART_UNIVERSAL_EXPLANATION"), SRC_POS);
- }
-
- // User profile
- wchar_t *configPath = GetConfigPath (L"dummy");
- if (configPath && towupper (configPath[0]) != windowsDrive)
- {
- throw ErrorException (wstring (GetString ("USER_PROFILE_NOT_ON_SYS_PARTITION"))
- + GetString ("LEAKS_OUTSIDE_SYSPART_UNIVERSAL_EXPLANATION"), SRC_POS);
- }
-
- // Temporary files
- if (towupper (GetTempPathString()[0]) != windowsDrive)
- {
- throw ErrorException (wstring (GetString ("TEMP_NOT_ON_SYS_PARTITION"))
- + GetString ("LEAKS_OUTSIDE_SYSPART_UNIVERSAL_EXPLANATION"), SRC_POS);
- }
- }
-
-
- // This operation may take a long time when an antivirus is installed and its real-time protection enabled.
- // Therefore, if calling it without the wizard displayed, it should be called with displayWaitDialog set to true.
- void BootEncryption::Deinstall (bool displayWaitDialog)
- {
- BootEncryptionStatus encStatus = GetStatus();
-
- if (encStatus.DriveEncrypted || encStatus.DriveMounted)
- throw ParameterIncorrect (SRC_POS);
-
- SystemDriveConfiguration config = GetSystemDriveConfiguration ();
-
- if (encStatus.VolumeHeaderPresent)
- {
- // Verify CRC of header salt
- Device device (config.DevicePath, true);
- device.CheckOpened (SRC_POS);
- byte header[TC_BOOT_ENCRYPTION_VOLUME_HEADER_SIZE];
-
- device.SeekAt (TC_BOOT_VOLUME_HEADER_SECTOR_OFFSET);
- device.Read (header, sizeof (header));
-
- if (encStatus.VolumeHeaderSaltCrc32 != GetCrc32 ((byte *) header, PKCS5_SALT_SIZE))
- throw ParameterIncorrect (SRC_POS);
- }
-
- try
- {
- RegisterFilterDriver (false, DriveFilter);
- RegisterFilterDriver (false, VolumeFilter);
- RegisterFilterDriver (false, DumpFilter);
- SetDriverServiceStartType (SERVICE_SYSTEM_START);
- }
- catch (...)
- {
- try
- {
- RegisterBootDriver (IsHiddenSystemRunning());
- }
- catch (...) { }
-
- throw;
- }
-
- SetHiddenOSCreationPhase (TC_HIDDEN_OS_CREATION_PHASE_NONE); // In case RestoreSystemLoader() fails
-
- try
- {
- RegisterSystemFavoritesService (false);
- }
- catch (...) { }
-
- try
- {
- if (displayWaitDialog)
- DisplayStaticModelessWaitDlg (ParentWindow);
-
- finally_do_arg (bool, displayWaitDialog, { if (finally_arg) CloseStaticModelessWaitDlg(); });
-
- RestoreSystemLoader ();
- }
- catch (Exception &e)
- {
- e.Show (ParentWindow);
- throw ErrorException ("SYS_LOADER_RESTORE_FAILED", SRC_POS);
- }
- }
-
-
- int BootEncryption::ChangePassword (Password *oldPassword, int old_pkcs5, int old_pim, Password *newPassword, int pkcs5, int pim, int wipePassCount, HWND hwndDlg)
- {
- BootEncryptionStatus encStatus = GetStatus();
-
- if (encStatus.SetupInProgress || (wipePassCount <= 0))
- throw ParameterIncorrect (SRC_POS);
-
- SystemDriveConfiguration config = GetSystemDriveConfiguration ();
-
- char header[TC_BOOT_ENCRYPTION_VOLUME_HEADER_SIZE];
- Device device (config.DevicePath);
- device.CheckOpened (SRC_POS);
-
- // Only one algorithm is currently supported
- if (pkcs5 != 0)
- throw ParameterIncorrect (SRC_POS);
-
- int64 headerOffset = TC_BOOT_VOLUME_HEADER_SECTOR_OFFSET;
- int64 backupHeaderOffset = -1;
-
- if (encStatus.HiddenSystem)
- {
- headerOffset = encStatus.HiddenSystemPartitionStart + TC_HIDDEN_VOLUME_HEADER_OFFSET;
-
- // Find hidden system partition
- foreach (const Partition &partition, config.Partitions)
- {
- if (partition.Info.StartingOffset.QuadPart == encStatus.HiddenSystemPartitionStart)
- {
- backupHeaderOffset = partition.Info.StartingOffset.QuadPart + partition.Info.PartitionLength.QuadPart - TC_VOLUME_HEADER_SIZE;
- break;
- }
- }
-
- if (backupHeaderOffset == -1)
- throw ParameterIncorrect (SRC_POS);
- }
-
- device.SeekAt (headerOffset);
- device.Read ((byte *) header, sizeof (header));
-
- PCRYPTO_INFO cryptoInfo = NULL;
-
- int status = ReadVolumeHeader (!encStatus.HiddenSystem, header, oldPassword, old_pkcs5, old_pim, FALSE, &cryptoInfo, NULL);
- finally_do_arg (PCRYPTO_INFO, cryptoInfo, { if (finally_arg) crypto_close (finally_arg); });
-
- if (status != 0)
- {
- handleError (hwndDlg, status, SRC_POS);
- return status;
- }
-
- // Change the PKCS-5 PRF if requested by user
- if (pkcs5 != 0)
- {
- cryptoInfo->pkcs5 = pkcs5;
- RandSetHashFunction (pkcs5);
- }
-
- if (Randinit() != 0)
- {
- if (CryptoAPILastError == ERROR_SUCCESS)
- throw RandInitFailed (SRC_POS, GetLastError ());
- else
- throw CryptoApiFailed (SRC_POS, CryptoAPILastError);
- }
- finally_do ({ RandStop (FALSE); });
-
- /* force the display of the random enriching dialog */
- SetRandomPoolEnrichedByUserStatus (FALSE);
-
- NormalCursor();
- UserEnrichRandomPool (hwndDlg);
- WaitCursor();
-
- /* The header will be re-encrypted wipePassCount times to prevent adversaries from using
- techniques such as magnetic force microscopy or magnetic force scanning tunnelling microscopy
- to recover the overwritten header. According to Peter Gutmann, data should be overwritten 22
- times (ideally, 35 times) using non-random patterns and pseudorandom data. However, as users might
- impatiently interupt the process (etc.) we will not use the Gutmann's patterns but will write the
- valid re-encrypted header, i.e. pseudorandom data, and there will be many more passes than Guttman
- recommends. During each pass we will write a valid working header. Each pass will use the same master
- key, and also the same header key, secondary key (XTS), etc., derived from the new password. The only
- item that will be different for each pass will be the salt. This is sufficient to cause each "version"
- of the header to differ substantially and in a random manner from the versions written during the
- other passes. */
-
- bool headerUpdated = false;
- int result = ERR_SUCCESS;
-
- try
- {
- BOOL backupHeader = FALSE;
- while (TRUE)
- {
- for (int wipePass = 0; wipePass < wipePassCount; wipePass++)
- {
- PCRYPTO_INFO tmpCryptoInfo = NULL;
-
- status = CreateVolumeHeaderInMemory (hwndDlg, !encStatus.HiddenSystem,
- header,
- cryptoInfo->ea,
- cryptoInfo->mode,
- newPassword,
- cryptoInfo->pkcs5,
- pim,
- (char *) cryptoInfo->master_keydata,
- &tmpCryptoInfo,
- cryptoInfo->VolumeSize.Value,
- cryptoInfo->hiddenVolumeSize,
- cryptoInfo->EncryptedAreaStart.Value,
- cryptoInfo->EncryptedAreaLength.Value,
- cryptoInfo->RequiredProgramVersion,
- cryptoInfo->HeaderFlags | TC_HEADER_FLAG_ENCRYPTED_SYSTEM,
- cryptoInfo->SectorSize,
- wipePass < wipePassCount - 1);
-
- if (tmpCryptoInfo)
- crypto_close (tmpCryptoInfo);
-
- if (status != 0)
- {
- handleError (hwndDlg, status, SRC_POS);
- return status;
- }
-
- device.SeekAt (headerOffset);
- device.Write ((byte *) header, sizeof (header));
- headerUpdated = true;
- }
-
- if (!encStatus.HiddenSystem || backupHeader)
- break;
-
- backupHeader = TRUE;
- headerOffset = backupHeaderOffset;
- }
- }
- catch (Exception &e)
- {
- e.Show (hwndDlg);
- result = ERR_OS_ERROR;
- }
-
- if (headerUpdated)
- {
- bool storedPimUpdateNeeded = false;
- ReopenBootVolumeHeaderRequest reopenRequest;
- reopenRequest.VolumePassword = *newPassword;
- reopenRequest.pkcs5_prf = cryptoInfo->pkcs5;
- reopenRequest.pim = pim;
- finally_do_arg (ReopenBootVolumeHeaderRequest*, &reopenRequest, { burn (finally_arg, sizeof (*finally_arg)); });
-
- if (old_pim != pim)
- {
- try
- {
- // check if PIM is stored in MBR
- byte userConfig;
- ReadBootSectorConfig (nullptr, 0, &userConfig);
- if (userConfig & TC_BOOT_USER_CFG_FLAG_DISABLE_PIM)
- storedPimUpdateNeeded = true;
- }
- catch (...)
- {}
- }
-
- try
- {
- // force update of bootloader if fingerprint doesn't match or if the stored PIM changed
- if (storedPimUpdateNeeded || !CheckBootloaderFingerprint (true))
- InstallBootLoader (device, true, false, pim);
- }
- catch (...)
- {}
-
- CallDriver (TC_IOCTL_REOPEN_BOOT_VOLUME_HEADER, &reopenRequest, sizeof (reopenRequest));
- }
-
- return result;
- }
-
-
- void BootEncryption::CheckEncryptionSetupResult ()
- {
- CallDriver (TC_IOCTL_GET_BOOT_ENCRYPTION_SETUP_RESULT);
- }
-
-
- void BootEncryption::Install (bool hiddenSystem)
- {
- BootEncryptionStatus encStatus = GetStatus();
- if (encStatus.DriveMounted)
- throw ParameterIncorrect (SRC_POS);
-
- try
- {
- InstallBootLoader (false, hiddenSystem);
-
- if (!hiddenSystem)
- InstallVolumeHeader ();
-
- RegisterBootDriver (hiddenSystem);
- }
- catch (Exception &)
- {
- try
- {
- RestoreSystemLoader ();
- }
- catch (Exception &e)
- {
- e.Show (ParentWindow);
- }
-
- throw;
- }
- }
-
-
- void BootEncryption::PrepareHiddenOSCreation (int ea, int mode, int pkcs5)
- {
- BootEncryptionStatus encStatus = GetStatus();
- if (encStatus.DriveMounted)
- throw ParameterIncorrect (SRC_POS);
-
- CheckRequirements();
- BackupSystemLoader();
-
- SelectedEncryptionAlgorithmId = ea;
- SelectedPrfAlgorithmId = pkcs5;
- }
-
-
- void BootEncryption::PrepareInstallation (bool systemPartitionOnly, Password &password, int ea, int mode, int pkcs5, int pim, const wstring &rescueIsoImagePath)
- {
- BootEncryptionStatus encStatus = GetStatus();
- if (encStatus.DriveMounted)
- throw ParameterIncorrect (SRC_POS);
-
- CheckRequirements ();
-
- SystemDriveConfiguration config = GetSystemDriveConfiguration();
-
- // Some chipset drivers may prevent access to the last sector of the drive
- if (!systemPartitionOnly)
- {
- DISK_GEOMETRY geometry = GetDriveGeometry (config.DriveNumber);
- if ((geometry.BytesPerSector > 0) && (geometry.BytesPerSector < TC_MAX_VOLUME_SECTOR_SIZE))
- {
- Buffer sector (geometry.BytesPerSector);
-
- Device device (config.DevicePath);
- device.CheckOpened (SRC_POS);
-
- try
- {
- device.SeekAt (config.DrivePartition.Info.PartitionLength.QuadPart - geometry.BytesPerSector);
- device.Read (sector.Ptr(), (DWORD) sector.Size());
- }
- catch (SystemException &e)
- {
- if (e.ErrorCode != ERROR_CRC)
- {
- e.Show (ParentWindow);
- Error ("WHOLE_DRIVE_ENCRYPTION_PREVENTED_BY_DRIVERS", ParentWindow);
- throw UserAbort (SRC_POS);
- }
- }
- }
- }
-
- BackupSystemLoader ();
-
- uint64 volumeSize;
- uint64 encryptedAreaStart;
-
- if (systemPartitionOnly)
- {
- volumeSize = config.SystemPartition.Info.PartitionLength.QuadPart;
- encryptedAreaStart = config.SystemPartition.Info.StartingOffset.QuadPart;
- }
- else
- {
- volumeSize = config.DrivePartition.Info.PartitionLength.QuadPart - TC_BOOT_LOADER_AREA_SIZE;
- encryptedAreaStart = config.DrivePartition.Info.StartingOffset.QuadPart + TC_BOOT_LOADER_AREA_SIZE;
- }
-
- SelectedEncryptionAlgorithmId = ea;
- SelectedPrfAlgorithmId = pkcs5;
- CreateVolumeHeader (volumeSize, encryptedAreaStart, &password, ea, mode, pkcs5, pim);
-
- if (!rescueIsoImagePath.empty())
- CreateRescueIsoImage (true, rescueIsoImagePath);
- }
-
- bool BootEncryption::IsPagingFileActive (BOOL checkNonWindowsPartitionsOnly)
- {
- if (!IsAdmin() && IsUacSupported())
- return Elevator::IsPagingFileActive (checkNonWindowsPartitionsOnly) ? true : false;
-
- return ::IsPagingFileActive (checkNonWindowsPartitionsOnly) ? true : false;
- }
-
- void BootEncryption::RestrictPagingFilesToSystemPartition ()
- {
- wchar_t pagingFiles[128] = {0};
- StringCchCopyW (pagingFiles, ARRAYSIZE(pagingFiles), L"X:\\pagefile.sys 0 0");
- pagingFiles[0] = GetWindowsDirectory()[0];
-
- throw_sys_if (!WriteLocalMachineRegistryMultiString (L"System\\CurrentControlSet\\Control\\Session Manager\\Memory Management", L"PagingFiles", pagingFiles, (DWORD) (wcslen (pagingFiles) + 2) * sizeof (wchar_t)));
- }
-
- void BootEncryption::WriteLocalMachineRegistryDwordValue (wchar_t *keyPath, wchar_t *valueName, DWORD value)
- {
- if (!IsAdmin() && IsUacSupported())
- {
- Elevator::WriteLocalMachineRegistryDwordValue (keyPath, valueName, value);
- return;
- }
-
- throw_sys_if (!WriteLocalMachineRegistryDword (keyPath, valueName, value));
- }
-
- void BootEncryption::StartDecryption (BOOL discardUnreadableEncryptedSectors)
- {
- BootEncryptionStatus encStatus = GetStatus();
-
- if (!encStatus.DeviceFilterActive || !encStatus.DriveMounted || encStatus.SetupInProgress)
- throw ParameterIncorrect (SRC_POS);
-
- BootEncryptionSetupRequest request;
- ZeroMemory (&request, sizeof (request));
-
- request.SetupMode = SetupDecryption;
- request.DiscardUnreadableEncryptedSectors = discardUnreadableEncryptedSectors;
-
- CallDriver (TC_IOCTL_BOOT_ENCRYPTION_SETUP, &request, sizeof (request), NULL, 0);
- }
-
- void BootEncryption::StartEncryption (WipeAlgorithmId wipeAlgorithm, bool zeroUnreadableSectors)
- {
- BootEncryptionStatus encStatus = GetStatus();
-
- if (!encStatus.DeviceFilterActive || !encStatus.DriveMounted || encStatus.SetupInProgress)
- throw ParameterIncorrect (SRC_POS);
-
- BootEncryptionSetupRequest request;
- ZeroMemory (&request, sizeof (request));
-
- request.SetupMode = SetupEncryption;
- request.WipeAlgorithm = wipeAlgorithm;
- request.ZeroUnreadableSectors = zeroUnreadableSectors;
-
- CallDriver (TC_IOCTL_BOOT_ENCRYPTION_SETUP, &request, sizeof (request), NULL, 0);
- }
-
- void BootEncryption::CopyFileAdmin (const wstring &sourceFile, const wstring &destinationFile)
- {
- if (!IsAdmin())
- {
- if (!IsUacSupported())
- {
- SetLastError (ERROR_ACCESS_DENIED);
- throw SystemException(SRC_POS);
- }
- else
- Elevator::CopyFile (sourceFile, destinationFile);
- }
- else
- throw_sys_if (!::CopyFile (sourceFile.c_str(), destinationFile.c_str(), FALSE));
- }
-
- void BootEncryption::DeleteFileAdmin (const wstring &file)
- {
- if (!IsAdmin() && IsUacSupported())
- Elevator::DeleteFile (file);
- else
- throw_sys_if (!::DeleteFile (file.c_str()));
- }
-
-#endif // !SETUP
-
- uint32 BootEncryption::ReadDriverConfigurationFlags ()
- {
- DWORD configMap;
-
- if (!ReadLocalMachineRegistryDword (L"SYSTEM\\CurrentControlSet\\Services\\veracrypt", TC_DRIVER_CONFIG_REG_VALUE_NAME, &configMap))
- configMap = 0;
-
- return configMap;
- }
-
- void BootEncryption::WriteBootDriveSector (uint64 offset, byte *data)
- {
- WriteBootDriveSectorRequest request;
- request.Offset.QuadPart = offset;
- memcpy (request.Data, data, sizeof (request.Data));
-
- CallDriver (TC_IOCTL_WRITE_BOOT_DRIVE_SECTOR, &request, sizeof (request), NULL, 0);
- }
-
- void BootEncryption::RegisterBootDriver (bool hiddenSystem)
- {
- SetDriverServiceStartType (SERVICE_BOOT_START);
-
- try
- {
- RegisterFilterDriver (false, DriveFilter);
- RegisterFilterDriver (false, VolumeFilter);
- RegisterFilterDriver (false, DumpFilter);
- }
- catch (...) { }
-
- try
- {
- RegisterFilterDriver (true, DriveFilter);
-
- if (hiddenSystem)
- RegisterFilterDriver (true, VolumeFilter);
-
- RegisterFilterDriver (true, DumpFilter);
- }
- catch (...)
- {
- try { RegisterFilterDriver (false, DriveFilter); } catch (...) { }
- try { RegisterFilterDriver (false, VolumeFilter); } catch (...) { }
- try { RegisterFilterDriver (false, DumpFilter); } catch (...) { }
- try { SetDriverServiceStartType (SERVICE_SYSTEM_START); } catch (...) { }
-
- throw;
- }
- }
-
- bool BootEncryption::RestartComputer (void)
- {
- return (::RestartComputer() != FALSE);
- }
-}
+/* + Derived from source code of TrueCrypt 7.1a, which is + Copyright (c) 2008-2012 TrueCrypt Developers Association and which is governed + by the TrueCrypt License 3.0. + + Modifications and additions to the original source code (contained in this file) + and all other portions of this file are Copyright (c) 2013-2016 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 "Platform/Finally.h" +#include "Platform/ForEach.h" +#include <devguid.h> +#include <io.h> +#include <shlobj.h> +#include <atlbase.h> +#include "BootEncryption.h" +#include "Boot/Windows/BootCommon.h" +#include "Common/Resource.h" +#include "Crc.h" +#include "Crypto.h" +#include "Dlgcode.h" +#include "Endian.h" +#include "Language.h" +#include "Random.h" +#include "Registry.h" +#include "Volumes.h" + +#ifdef VOLFORMAT +#include "Format/FormatCom.h" +#elif defined (TCMOUNT) +#include "Mount/MainCom.h" +#endif + +#include <Strsafe.h> + +namespace VeraCrypt +{ +#if !defined (SETUP) + + class Elevator + { + public: + + static void AddReference () + { + ++ReferenceCount; + } + + + static void CallDriver (DWORD ioctl, void *input, DWORD inputSize, void *output, DWORD outputSize) + { + Elevate(); + + CComBSTR inputBstr; + if (input && inputBstr.AppendBytes ((const char *) input, inputSize) != S_OK) + throw ParameterIncorrect (SRC_POS); + + CComBSTR outputBstr; + if (output && outputBstr.AppendBytes ((const char *) output, outputSize) != S_OK) + throw ParameterIncorrect (SRC_POS); + + DWORD result = ElevatedComInstance->CallDriver (ioctl, inputBstr, &outputBstr); + + if (output) + memcpy (output, *(void **) &outputBstr, outputSize); + + if (result != ERROR_SUCCESS) + { + SetLastError (result); + throw SystemException(SRC_POS); + } + } + + static void CopyFile (const wstring &sourceFile, const wstring &destinationFile) + { + Elevate(); + DWORD result; + CComBSTR sourceFileBstr, destinationFileBstr; + BSTR bstr = W2BSTR(sourceFile.c_str()); + if (bstr) + { + sourceFileBstr.Attach (bstr); + + bstr = W2BSTR(destinationFile.c_str()); + if (bstr) + { + destinationFileBstr.Attach (bstr); + result = ElevatedComInstance->CopyFile (sourceFileBstr, destinationFileBstr); + } + else + { + result = ERROR_OUTOFMEMORY; + } + } + else + { + result = ERROR_OUTOFMEMORY; + } + + if (result != ERROR_SUCCESS) + { + SetLastError (result); + throw SystemException(SRC_POS); + } + } + + static void DeleteFile (const wstring &file) + { + Elevate(); + CComBSTR fileBstr; + DWORD result; + BSTR bstr = W2BSTR(file.c_str()); + if (bstr) + { + fileBstr.Attach (bstr); + result = ElevatedComInstance->DeleteFile (fileBstr); + } + else + { + result = ERROR_OUTOFMEMORY; + } + + if (result != ERROR_SUCCESS) + { + SetLastError (result); + throw SystemException(SRC_POS); + } + } + + static void ReadWriteFile (BOOL write, BOOL device, const wstring &filePath, byte *buffer, uint64 offset, uint32 size, DWORD *sizeDone) + { + Elevate(); + + DWORD result; + CComBSTR bufferBstr, fileBstr; + if (bufferBstr.AppendBytes ((const char *) buffer, size) != S_OK) + throw ParameterIncorrect (SRC_POS); + BSTR bstr = W2BSTR(filePath.c_str()); + if (bstr) + { + fileBstr.Attach (bstr); + result = ElevatedComInstance->ReadWriteFile (write, device, fileBstr, &bufferBstr, offset, size, sizeDone); + } + else + { + result = ERROR_OUTOFMEMORY; + } + + if (result != ERROR_SUCCESS) + { + SetLastError (result); + throw SystemException(SRC_POS); + } + + if (!write) + memcpy (buffer, (BYTE *) bufferBstr.m_str, size); + } + + static BOOL IsPagingFileActive (BOOL checkNonWindowsPartitionsOnly) + { + Elevate(); + + return ElevatedComInstance->IsPagingFileActive (checkNonWindowsPartitionsOnly); + } + + static void WriteLocalMachineRegistryDwordValue (wchar_t *keyPath, wchar_t *valueName, DWORD value) + { + Elevate(); + DWORD result; + CComBSTR keyPathBstr, valueNameBstr; + BSTR bstr = W2BSTR(keyPath); + if (bstr) + { + keyPathBstr.Attach (bstr); + + bstr = W2BSTR(valueName); + if (bstr) + { + valueNameBstr.Attach (bstr); + + result = ElevatedComInstance->WriteLocalMachineRegistryDwordValue (keyPathBstr, valueNameBstr, value); + } + else + { + result = ERROR_OUTOFMEMORY; + } + } + else + { + result = ERROR_OUTOFMEMORY; + } + + if (result != ERROR_SUCCESS) + { + SetLastError (result); + throw SystemException(SRC_POS); + } + } + + static void RegisterFilterDriver (bool registerDriver, BootEncryption::FilterType filterType) + { + Elevate(); + + DWORD result = ElevatedComInstance->RegisterFilterDriver (registerDriver ? TRUE : FALSE, filterType); + if (result != ERROR_SUCCESS) + { + SetLastError (result); + throw SystemException(SRC_POS); + } + } + + static void RegisterSystemFavoritesService (BOOL registerService) + { + Elevate(); + + DWORD result = ElevatedComInstance->RegisterSystemFavoritesService (registerService); + if (result != ERROR_SUCCESS) + { + SetLastError (result); + throw SystemException(SRC_POS); + } + } + + static void Release () + { + if (--ReferenceCount == 0 && ElevatedComInstance) + { + ElevatedComInstance->Release(); + ElevatedComInstance = nullptr; + CoUninitialize (); + } + } + + static void SetDriverServiceStartType (DWORD startType) + { + Elevate(); + + DWORD result = ElevatedComInstance->SetDriverServiceStartType (startType); + if (result != ERROR_SUCCESS) + { + SetLastError (result); + throw SystemException(SRC_POS); + } + } + + protected: + static void Elevate () + { + if (IsAdmin()) + { + SetLastError (ERROR_ACCESS_DENIED); + throw SystemException(SRC_POS); + } + + if (!ElevatedComInstance || ElevatedComInstanceThreadId != GetCurrentThreadId()) + { + CoInitialize (NULL); + ElevatedComInstance = GetElevatedInstance (GetActiveWindow() ? GetActiveWindow() : MainDlg); + ElevatedComInstanceThreadId = GetCurrentThreadId(); + } + } + +#if defined (TCMOUNT) + static ITrueCryptMainCom *ElevatedComInstance; +#elif defined (VOLFORMAT) + static ITrueCryptFormatCom *ElevatedComInstance; +#endif + static DWORD ElevatedComInstanceThreadId; + static int ReferenceCount; + }; + +#if defined (TCMOUNT) + ITrueCryptMainCom *Elevator::ElevatedComInstance; +#elif defined (VOLFORMAT) + ITrueCryptFormatCom *Elevator::ElevatedComInstance; +#endif + DWORD Elevator::ElevatedComInstanceThreadId; + int Elevator::ReferenceCount = 0; + +#else // SETUP + + class Elevator + { + public: + static void AddReference () { } + static void CallDriver (DWORD ioctl, void *input, DWORD inputSize, void *output, DWORD outputSize) { throw ParameterIncorrect (SRC_POS); } + static void ReadWriteFile (BOOL write, BOOL device, const wstring &filePath, byte *buffer, uint64 offset, uint32 size, DWORD *sizeDone) { throw ParameterIncorrect (SRC_POS); } + static void RegisterFilterDriver (bool registerDriver, BootEncryption::FilterType filterType) { throw ParameterIncorrect (SRC_POS); } + static void Release () { } + static void SetDriverServiceStartType (DWORD startType) { throw ParameterIncorrect (SRC_POS); } + }; + +#endif // SETUP + + + File::File (wstring path, bool readOnly, bool create) : Elevated (false), FileOpen (false), LastError(0) + { + Handle = CreateFile (path.c_str(), + readOnly ? GENERIC_READ : GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, create ? CREATE_ALWAYS : OPEN_EXISTING, + FILE_FLAG_RANDOM_ACCESS | FILE_FLAG_WRITE_THROUGH, NULL); + + if (Handle != INVALID_HANDLE_VALUE) + { + FileOpen = true; + } + else + { + LastError = GetLastError(); + if (LastError == ERROR_ACCESS_DENIED && IsUacSupported()) + { + Elevated = true; + FileOpen = true; + } + } + + FilePointerPosition = 0; + IsDevice = false; + Path = path; + } + + void File::Close () + { + if (Handle != INVALID_HANDLE_VALUE) + { + CloseHandle (Handle); + Handle = INVALID_HANDLE_VALUE; + } + + FileOpen = false; + } + + DWORD File::Read (byte *buffer, DWORD size) + { + DWORD bytesRead; + + if (!FileOpen) + { + SetLastError (LastError); + throw SystemException (SRC_POS); + } + + if (Elevated) + { + DWORD bytesRead; + + Elevator::ReadWriteFile (false, IsDevice, Path, buffer, FilePointerPosition, size, &bytesRead); + FilePointerPosition += bytesRead; + return bytesRead; + } + + throw_sys_if (!ReadFile (Handle, buffer, size, &bytesRead, NULL)); + return bytesRead; + } + + void File::SeekAt (int64 position) + { + if (!FileOpen) + { + SetLastError (LastError); + throw SystemException (SRC_POS); + } + + FilePointerPosition = position; + + if (!Elevated) + { + LARGE_INTEGER pos; + pos.QuadPart = position; + throw_sys_if (!SetFilePointerEx (Handle, pos, NULL, FILE_BEGIN)); + } + } + + void File::Write (byte *buffer, DWORD size) + { + DWORD bytesWritten; + + if (!FileOpen) + { + SetLastError (LastError); + throw SystemException (SRC_POS); + } + + try + { + if (Elevated) + { + Elevator::ReadWriteFile (true, IsDevice, Path, buffer, FilePointerPosition, size, &bytesWritten); + FilePointerPosition += bytesWritten; + throw_sys_if (bytesWritten != size); + } + else + { + throw_sys_if (!WriteFile (Handle, buffer, size, &bytesWritten, NULL) || bytesWritten != size); + } + } + catch (SystemException &e) + { + if (!IsDevice || e.ErrorCode != ERROR_WRITE_PROTECT) + throw; + + BootEncryption bootEnc (NULL); + + while (size >= TC_SECTOR_SIZE_BIOS) + { + bootEnc.WriteBootDriveSector (FilePointerPosition, buffer); + + FilePointerPosition += TC_SECTOR_SIZE_BIOS; + buffer += TC_SECTOR_SIZE_BIOS; + size -= TC_SECTOR_SIZE_BIOS; + } + } + } + + void Show (HWND parent, const wstring &str) + { + MessageBox (parent, str.c_str(), NULL, 0); + } + + + Device::Device (wstring path, bool readOnly) + { + FileOpen = false; + Elevated = false; + + Handle = CreateFile ((wstring (L"\\\\.\\") + path).c_str(), + readOnly ? GENERIC_READ : GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, + FILE_FLAG_RANDOM_ACCESS | FILE_FLAG_WRITE_THROUGH, NULL); + + if (Handle != INVALID_HANDLE_VALUE) + { + FileOpen = true; + } + else + { + LastError = GetLastError (); + if (LastError == ERROR_ACCESS_DENIED && IsUacSupported()) + { + Elevated = true; + FileOpen = true; + } + } + + FilePointerPosition = 0; + IsDevice = true; + Path = path; + } + + + BootEncryption::BootEncryption (HWND parent) + : DriveConfigValid (false), + ParentWindow (parent), + RealSystemDriveSizeValid (false), + RescueIsoImage (nullptr), + RescueVolumeHeaderValid (false), + SelectedEncryptionAlgorithmId (0), + SelectedPrfAlgorithmId (0), + VolumeHeaderValid (false) + { + HiddenOSCandidatePartition.IsGPT = FALSE; + HiddenOSCandidatePartition.Number = (size_t) -1; + DriveConfig.DriveNumber = -1; + DriveConfig.ExtraBootPartitionPresent = false; + DriveConfig.SystemLoaderPresent = false; + DriveConfig.InitialUnallocatedSpace = 0; + DriveConfig.TotalUnallocatedSpace = 0; + Elevator::AddReference(); + } + + + BootEncryption::~BootEncryption () + { + if (RescueIsoImage) + delete[] RescueIsoImage; + + Elevator::Release(); + } + + + void BootEncryption::CallDriver (DWORD ioctl, void *input, DWORD inputSize, void *output, DWORD outputSize) + { + try + { + DWORD bytesReturned; + throw_sys_if (!DeviceIoControl (hDriver, ioctl, input, inputSize, output, outputSize, &bytesReturned, NULL)); + } + catch (SystemException &) + { + if (GetLastError() == ERROR_ACCESS_DENIED && IsUacSupported()) + Elevator::CallDriver (ioctl, input, inputSize, output, outputSize); + else + throw; + } + } + + + // Finds the first partition physically located behind the active one and returns its properties + Partition BootEncryption::GetPartitionForHiddenOS () + { + Partition candidatePartition; + + memset (&candidatePartition, 0, sizeof(candidatePartition)); + + // The user may have modified/added/deleted partitions since the time the partition table was last scanned + InvalidateCachedSysDriveProperties(); + + SystemDriveConfiguration config = GetSystemDriveConfiguration (); + bool activePartitionFound = false; + bool candidateForHiddenOSFound = false; + + if (config.SystemPartition.IsGPT) + throw ParameterIncorrect (SRC_POS); // It is assumed that CheckRequirements() had been called + + // Find the first active partition on the system drive + foreach (const Partition &partition, config.Partitions) + { + if (partition.Info.BootIndicator) + { + if (partition.Info.PartitionNumber != config.SystemPartition.Number) + { + // If there is an extra boot partition, the system partition must be located right behind it + if (IsOSAtLeast (WIN_7) && config.ExtraBootPartitionPresent) + { + int64 minOffsetFound = config.DrivePartition.Info.PartitionLength.QuadPart; + Partition bootPartition = partition; + Partition partitionBehindBoot; + + foreach (const Partition &partition, config.Partitions) + { + if (partition.Info.StartingOffset.QuadPart > bootPartition.Info.StartingOffset.QuadPart + && partition.Info.StartingOffset.QuadPart < minOffsetFound) + { + minOffsetFound = partition.Info.StartingOffset.QuadPart; + partitionBehindBoot = partition; + } + } + + if (minOffsetFound != config.DrivePartition.Info.PartitionLength.QuadPart + && partitionBehindBoot.Number == config.SystemPartition.Number) + { + activePartitionFound = true; + break; + } + } + + throw ErrorException (wstring (GetString ("SYSTEM_PARTITION_NOT_ACTIVE")) + + GetRemarksOnHiddenOS(), SRC_POS); + } + + activePartitionFound = true; + break; + } + } + + /* WARNING: Note that the partition number at the end of a device path (\Device\HarddiskY\PartitionX) must + NOT be used to find the first partition physically located behind the active one. The reason is that the + user may have deleted and created partitions during this session and e.g. the second partition could have + a higer number than the third one. */ + + + // Find the first partition physically located behind the active partition + if (activePartitionFound) + { + int64 minOffsetFound = config.DrivePartition.Info.PartitionLength.QuadPart; + + foreach (const Partition &partition, config.Partitions) + { + if (partition.Info.StartingOffset.QuadPart > config.SystemPartition.Info.StartingOffset.QuadPart + && partition.Info.StartingOffset.QuadPart < minOffsetFound) + { + minOffsetFound = partition.Info.StartingOffset.QuadPart; + + candidatePartition = partition; + + candidateForHiddenOSFound = true; + } + } + + if (!candidateForHiddenOSFound) + { + throw ErrorException (wstring (GetString ("NO_PARTITION_FOLLOWS_BOOT_PARTITION")) + + GetRemarksOnHiddenOS(), SRC_POS); + } + + if (config.SystemPartition.Info.PartitionLength.QuadPart > TC_MAX_FAT_SECTOR_COUNT * TC_SECTOR_SIZE_BIOS) + { + if ((double) candidatePartition.Info.PartitionLength.QuadPart / config.SystemPartition.Info.PartitionLength.QuadPart < MIN_HIDDENOS_DECOY_PARTITION_SIZE_RATIO_NTFS) + { + throw ErrorException (wstring (GetString ("PARTITION_TOO_SMALL_FOR_HIDDEN_OS_NTFS")) + + GetRemarksOnHiddenOS(), SRC_POS); + } + } + else if ((double) candidatePartition.Info.PartitionLength.QuadPart / config.SystemPartition.Info.PartitionLength.QuadPart < MIN_HIDDENOS_DECOY_PARTITION_SIZE_RATIO_FAT) + { + throw ErrorException (wstring (GetString ("PARTITION_TOO_SMALL_FOR_HIDDEN_OS")) + + GetRemarksOnHiddenOS(), SRC_POS); + } + } + else + { + // No active partition on the system drive + throw ErrorException ("SYSTEM_PARTITION_NOT_ACTIVE", SRC_POS); + } + + HiddenOSCandidatePartition = candidatePartition; + return candidatePartition; + } + + + DWORD BootEncryption::GetDriverServiceStartType () + { + DWORD startType; + throw_sys_if (!ReadLocalMachineRegistryDword (L"SYSTEM\\CurrentControlSet\\Services\\veracrypt", L"Start", &startType)); + return startType; + } + + + wstring BootEncryption::GetRemarksOnHiddenOS () + { + return (wstring (L"\n\n") + + GetString ("TWO_SYSTEMS_IN_ONE_PARTITION_REMARK") + + L"\n\n" + + GetString ("FOR_MORE_INFO_ON_PARTITIONS")); + } + + + void BootEncryption::SetDriverServiceStartType (DWORD startType) + { + if (!IsAdmin() && IsUacSupported()) + { + Elevator::SetDriverServiceStartType (startType); + return; + } + + BOOL startOnBoot = (startType == SERVICE_BOOT_START); + + SC_HANDLE serviceManager = OpenSCManager (NULL, NULL, SC_MANAGER_ALL_ACCESS); + throw_sys_if (!serviceManager); + + finally_do_arg (SC_HANDLE, serviceManager, { CloseServiceHandle (finally_arg); }); + + SC_HANDLE service = OpenService (serviceManager, L"veracrypt", SERVICE_CHANGE_CONFIG); + throw_sys_if (!service); + + finally_do_arg (SC_HANDLE, service, { CloseServiceHandle (finally_arg); }); + + // Windows versions preceding Vista can be installed on FAT filesystem which does not + // support long filenames during boot. Convert the driver path to short form if required. + wstring driverPath; + if (startOnBoot && !IsOSAtLeast (WIN_VISTA)) + { + wchar_t pathBuf[MAX_PATH]; + wchar_t filesystem[128]; + + wstring path (GetWindowsDirectory()); + path += L"\\drivers\\veracrypt.sys"; + + if (GetVolumePathName (path.c_str(), pathBuf, ARRAYSIZE (pathBuf)) + && GetVolumeInformation (pathBuf, NULL, 0, NULL, NULL, NULL, filesystem, ARRAYSIZE(filesystem)) + && wmemcmp (filesystem, L"FAT", 3) == 0) + { + throw_sys_if (GetShortPathName (path.c_str(), pathBuf, ARRAYSIZE (pathBuf)) == 0); + + // Convert absolute path to relative to the Windows directory + driverPath = pathBuf; + driverPath = driverPath.substr (driverPath.rfind (L"\\", driverPath.rfind (L"\\", driverPath.rfind (L"\\") - 1) - 1) + 1); + } + } + + throw_sys_if (!ChangeServiceConfig (service, SERVICE_NO_CHANGE, SERVICE_NO_CHANGE, + startOnBoot ? SERVICE_ERROR_SEVERE : SERVICE_ERROR_NORMAL, + driverPath.empty() ? NULL : driverPath.c_str(), + startOnBoot ? L"Filter" : NULL, + NULL, NULL, NULL, NULL, NULL)); + + // ChangeServiceConfig() rejects SERVICE_BOOT_START with ERROR_INVALID_PARAMETER + throw_sys_if (!WriteLocalMachineRegistryDword (L"SYSTEM\\CurrentControlSet\\Services\\veracrypt", L"Start", startType)); + } + + + void BootEncryption::ProbeRealSystemDriveSize () + { + if (RealSystemDriveSizeValid) + return; + + GetSystemDriveConfiguration(); + + ProbeRealDriveSizeRequest request; + StringCchCopyW (request.DeviceName, ARRAYSIZE (request.DeviceName), DriveConfig.DrivePartition.DevicePath.c_str()); + + CallDriver (TC_IOCTL_PROBE_REAL_DRIVE_SIZE, &request, sizeof (request), &request, sizeof (request)); + DriveConfig.DrivePartition.Info.PartitionLength = request.RealDriveSize; + + RealSystemDriveSizeValid = true; + + if (request.TimeOut) + throw TimeOut (SRC_POS); + } + + + void BootEncryption::InvalidateCachedSysDriveProperties () + { + DriveConfigValid = false; + RealSystemDriveSizeValid = false; + } + + + PartitionList BootEncryption::GetDrivePartitions (int driveNumber) + { + PartitionList partList; + + for (int partNumber = 0; partNumber < 64; ++partNumber) + { + wstringstream partPath; + partPath << L"\\Device\\Harddisk" << driveNumber << L"\\Partition" << partNumber; + + DISK_PARTITION_INFO_STRUCT diskPartInfo = {0}; + StringCchCopyW (diskPartInfo.deviceName, ARRAYSIZE (diskPartInfo.deviceName), partPath.str().c_str()); + + try + { + CallDriver (TC_IOCTL_GET_DRIVE_PARTITION_INFO, &diskPartInfo, sizeof (diskPartInfo), &diskPartInfo, sizeof (diskPartInfo)); + } + catch (...) + { + continue; + } + + if ( (diskPartInfo.IsGPT == TRUE || diskPartInfo.IsGPT == FALSE) + && (diskPartInfo.IsDynamic == TRUE || diskPartInfo.IsDynamic == FALSE) + && (diskPartInfo.partInfo.BootIndicator == TRUE || diskPartInfo.partInfo.BootIndicator == FALSE) + && (diskPartInfo.partInfo.RecognizedPartition == TRUE || diskPartInfo.partInfo.RecognizedPartition == FALSE) + && (diskPartInfo.partInfo.RewritePartition == TRUE || diskPartInfo.partInfo.RewritePartition == FALSE) + && (diskPartInfo.partInfo.StartingOffset.QuadPart >= 0) + && (diskPartInfo.partInfo.PartitionLength.QuadPart >= 0) + ) + { + Partition part; + part.DevicePath = partPath.str(); + part.Number = partNumber; + part.Info = diskPartInfo.partInfo; + part.IsGPT = diskPartInfo.IsGPT; + + // Mount point + int driveNumber = GetDiskDeviceDriveLetter ((wchar_t *) partPath.str().c_str()); + + if (driveNumber >= 0) + { + part.MountPoint += (wchar_t) (driveNumber + L'A'); + part.MountPoint += L":"; + } + + // Volume ID + wchar_t volumePath[TC_MAX_PATH]; + if (ResolveSymbolicLink ((wchar_t *) partPath.str().c_str(), volumePath, sizeof(volumePath))) + { + wchar_t volumeName[TC_MAX_PATH]; + HANDLE fh = FindFirstVolumeW (volumeName, array_capacity (volumeName)); + if (fh != INVALID_HANDLE_VALUE) + { + do + { + wstring volumeNameStr = volumeName; + wchar_t devicePath[TC_MAX_PATH]; + + if (QueryDosDeviceW (volumeNameStr.substr (4, volumeNameStr.size() - 1 - 4).c_str(), devicePath, array_capacity (devicePath)) != 0 + && wcscmp (volumePath, devicePath) == 0) + { + part.VolumeNameId = volumeName; + break; + } + + } while (FindNextVolumeW (fh, volumeName, array_capacity (volumeName))); + + FindVolumeClose (fh); + } + } + + partList.push_back (part); + } + } + + return partList; + } + + + DISK_GEOMETRY BootEncryption::GetDriveGeometry (int driveNumber) + { + wstringstream devName; + devName << L"\\Device\\Harddisk" << driveNumber << L"\\Partition0"; + + DISK_GEOMETRY geometry; + throw_sys_if (!::GetDriveGeometry (devName.str().c_str(), &geometry)); + return geometry; + } + + + wstring BootEncryption::GetWindowsDirectory () + { + wchar_t buf[MAX_PATH]; + throw_sys_if (GetSystemDirectory (buf, ARRAYSIZE (buf)) == 0); + + return wstring (buf); + } + + + + uint16 BootEncryption::GetInstalledBootLoaderVersion () + { + uint16 version; + CallDriver (TC_IOCTL_GET_BOOT_LOADER_VERSION, NULL, 0, &version, sizeof (version)); + return version; + } + + void BootEncryption::GetInstalledBootLoaderFingerprint (byte fingerprint[WHIRLPOOL_DIGESTSIZE + SHA512_DIGESTSIZE]) + { + BootLoaderFingerprintRequest request; + CallDriver (VC_IOCTL_GET_BOOT_LOADER_FINGERPRINT, NULL, 0, &request, sizeof (request)); + memcpy (fingerprint, request.Fingerprint, sizeof (request.Fingerprint)); + } + + // Note that this does not require admin rights (it just requires the driver to be running) + bool BootEncryption::IsBootLoaderOnDrive (wchar_t *devicePath) + { + try + { + OPEN_TEST_STRUCT openTestStruct; + memset (&openTestStruct, 0, sizeof (openTestStruct)); + DWORD dwResult; + + StringCchCopyW (&openTestStruct.wszFileName[0], ARRAYSIZE(openTestStruct.wszFileName),devicePath); + + openTestStruct.bDetectTCBootLoader = TRUE; + + return (DeviceIoControl (hDriver, TC_IOCTL_OPEN_TEST, + &openTestStruct, sizeof (OPEN_TEST_STRUCT), + &openTestStruct, sizeof (OPEN_TEST_STRUCT), + &dwResult, NULL) && openTestStruct.TCBootLoaderDetected); + } + catch (...) + { + return false; + } + } + + + BootEncryptionStatus BootEncryption::GetStatus () + { + /* IMPORTANT: Do NOT add any potentially time-consuming operations to this function. */ + + BootEncryptionStatus status; + CallDriver (TC_IOCTL_GET_BOOT_ENCRYPTION_STATUS, NULL, 0, &status, sizeof (status)); + return status; + } + + + void BootEncryption::GetVolumeProperties (VOLUME_PROPERTIES_STRUCT *properties) + { + if (properties == NULL) + throw ParameterIncorrect (SRC_POS); + + CallDriver (TC_IOCTL_GET_BOOT_DRIVE_VOLUME_PROPERTIES, NULL, 0, properties, sizeof (*properties)); + } + + + bool BootEncryption::IsHiddenSystemRunning () + { + int hiddenSystemStatus; + + CallDriver (TC_IOCTL_IS_HIDDEN_SYSTEM_RUNNING, nullptr, 0, &hiddenSystemStatus, sizeof (hiddenSystemStatus)); + return hiddenSystemStatus != 0; + } + + + bool BootEncryption::SystemDriveContainsPartitionType (byte type) + { + Device device (GetSystemDriveConfiguration().DevicePath, true); + device.CheckOpened (SRC_POS); + + byte mbrBuf[TC_SECTOR_SIZE_BIOS]; + device.SeekAt (0); + device.Read (mbrBuf, sizeof (mbrBuf)); + + MBR *mbr = reinterpret_cast <MBR *> (mbrBuf); + if (mbr->Signature != 0xaa55) + throw ParameterIncorrect (SRC_POS); + + for (size_t i = 0; i < array_capacity (mbr->Partitions); ++i) + { + if (mbr->Partitions[i].Type == type) + return true; + } + + return false; + } + + + bool BootEncryption::SystemDriveContainsExtendedPartition () + { + return SystemDriveContainsPartitionType (PARTITION_EXTENDED) || SystemDriveContainsPartitionType (PARTITION_XINT13_EXTENDED); + } + + + bool BootEncryption::SystemDriveContainsNonStandardPartitions () + { + for (int partitionType = 1; partitionType <= 0xff; ++partitionType) + { + switch (partitionType) + { + case PARTITION_FAT_12: + case PARTITION_FAT_16: + case PARTITION_EXTENDED: + case PARTITION_HUGE: + case PARTITION_IFS: + case PARTITION_FAT32: + case PARTITION_FAT32_XINT13: + case PARTITION_XINT13: + case PARTITION_XINT13_EXTENDED: + continue; + } + + if (SystemDriveContainsPartitionType ((byte) partitionType)) + return true; + } + + return false; + } + + + bool BootEncryption::SystemDriveIsDynamic () + { + GetSystemDriveConfigurationRequest request; + StringCchCopyW (request.DevicePath, ARRAYSIZE (request.DevicePath), GetSystemDriveConfiguration().DeviceKernelPath.c_str()); + + CallDriver (TC_IOCTL_GET_SYSTEM_DRIVE_CONFIG, &request, sizeof (request), &request, sizeof (request)); + return request.DriveIsDynamic ? true : false; + } + + + SystemDriveConfiguration BootEncryption::GetSystemDriveConfiguration () + { + if (DriveConfigValid) + return DriveConfig; + + SystemDriveConfiguration config; + + wstring winDir = GetWindowsDirectory(); + + // Scan all drives + for (int driveNumber = 0; driveNumber < 32; ++driveNumber) + { + bool windowsFound = false; + bool activePartitionFound = false; + config.ExtraBootPartitionPresent = false; + config.SystemLoaderPresent = false; + + PartitionList partitions = GetDrivePartitions (driveNumber); + foreach (const Partition &part, partitions) + { + if (!part.MountPoint.empty() + && (_waccess ((part.MountPoint + L"\\bootmgr").c_str(), 0) == 0 || _waccess ((part.MountPoint + L"\\ntldr").c_str(), 0) == 0)) + { + config.SystemLoaderPresent = true; + } + else if (!part.VolumeNameId.empty() + && (_waccess ((part.VolumeNameId + L"\\bootmgr").c_str(), 0) == 0 || _waccess ((part.VolumeNameId + L"\\ntldr").c_str(), 0) == 0)) + { + config.SystemLoaderPresent = true; + } + + if (!windowsFound && !part.MountPoint.empty() && ToUpperCase (winDir).find (ToUpperCase (part.MountPoint)) == 0) + { + config.SystemPartition = part; + windowsFound = true; + } + + if (!activePartitionFound && part.Info.BootIndicator) + { + activePartitionFound = true; + + if (part.Info.PartitionLength.QuadPart > 0 && part.Info.PartitionLength.QuadPart <= TC_MAX_EXTRA_BOOT_PARTITION_SIZE) + config.ExtraBootPartitionPresent = true; + } + } + + if (windowsFound) + { + config.DriveNumber = driveNumber; + + wstringstream ss; + ss << L"PhysicalDrive" << driveNumber; + config.DevicePath = ss.str(); + + wstringstream kernelPath; + kernelPath << L"\\Device\\Harddisk" << driveNumber << L"\\Partition0"; + config.DeviceKernelPath = kernelPath.str(); + + config.DrivePartition = partitions.front(); + partitions.pop_front(); + config.Partitions = partitions; + + config.InitialUnallocatedSpace = 0x7fffFFFFffffFFFFull; + config.TotalUnallocatedSpace = config.DrivePartition.Info.PartitionLength.QuadPart; + + foreach (const Partition &part, config.Partitions) + { + if (part.Info.StartingOffset.QuadPart < config.InitialUnallocatedSpace) + config.InitialUnallocatedSpace = part.Info.StartingOffset.QuadPart; + + config.TotalUnallocatedSpace -= part.Info.PartitionLength.QuadPart; + } + + DriveConfig = config; + DriveConfigValid = true; + return DriveConfig; + } + } + + throw ParameterIncorrect (SRC_POS); + } + + + bool BootEncryption::SystemPartitionCoversWholeDrive () + { + SystemDriveConfiguration config = GetSystemDriveConfiguration(); + + if (IsOSAtLeast (WIN_7) + && config.Partitions.size() == 2 + && config.ExtraBootPartitionPresent + && config.DrivePartition.Info.PartitionLength.QuadPart - config.SystemPartition.Info.PartitionLength.QuadPart < 164 * BYTES_PER_MB) + { + return true; + } + + return config.Partitions.size() == 1 + && config.DrivePartition.Info.PartitionLength.QuadPart - config.SystemPartition.Info.PartitionLength.QuadPart < 64 * BYTES_PER_MB; + } + + + uint32 BootEncryption::GetChecksum (byte *data, size_t size) + { + uint32 sum = 0; + + while (size-- > 0) + { + sum += *data++; + sum = _rotl (sum, 1); + } + + return sum; + } + + + void BootEncryption::CreateBootLoaderInMemory (byte *buffer, size_t bufferSize, bool rescueDisk, bool hiddenOSCreation) + { + if (bufferSize < TC_BOOT_LOADER_AREA_SIZE - TC_BOOT_ENCRYPTION_VOLUME_HEADER_SIZE) + throw ParameterIncorrect (SRC_POS); + + ZeroMemory (buffer, bufferSize); + + int ea = 0; + int pkcs5_prf = 0; + if (GetStatus().DriveMounted) + { + try + { + GetBootEncryptionAlgorithmNameRequest request; + // since we added new field to GetBootEncryptionAlgorithmNameRequest since version 1.0f + // we zero all the structure so that if we are talking to an older driver, the field + // BootPrfAlgorithmName will be an empty string + ZeroMemory(&request, sizeof(request)); + CallDriver (TC_IOCTL_GET_BOOT_ENCRYPTION_ALGORITHM_NAME, NULL, 0, &request, sizeof (request)); + + if (_stricmp (request.BootEncryptionAlgorithmName, "AES") == 0) + ea = AES; + else if (_stricmp (request.BootEncryptionAlgorithmName, "Serpent") == 0) + ea = SERPENT; + else if (_stricmp (request.BootEncryptionAlgorithmName, "Twofish") == 0) + ea = TWOFISH; + + if (_stricmp(request.BootPrfAlgorithmName, "SHA-256") == 0) + pkcs5_prf = SHA256; + else if (_stricmp(request.BootPrfAlgorithmName, "RIPEMD-160") == 0) + pkcs5_prf = RIPEMD160; + else if (strlen(request.BootPrfAlgorithmName) == 0) // case of version < 1.0f + pkcs5_prf = RIPEMD160; + } + catch (...) + { + try + { + VOLUME_PROPERTIES_STRUCT properties; + GetVolumeProperties (&properties); + ea = properties.ea; + pkcs5_prf = properties.pkcs5; + } + catch (...) { } + } + } + else + { + if (SelectedEncryptionAlgorithmId == 0 || SelectedPrfAlgorithmId == 0) + throw ParameterIncorrect (SRC_POS); + + ea = SelectedEncryptionAlgorithmId; + pkcs5_prf = SelectedPrfAlgorithmId; + } + + // Only RIPEMD160 and SHA-256 are supported for boot loader + if (pkcs5_prf != RIPEMD160 && pkcs5_prf != SHA256) + throw ParameterIncorrect (SRC_POS); + + int bootSectorId = 0; + int bootLoaderId = 0; + + if (pkcs5_prf == SHA256) + { + bootSectorId = rescueDisk ? IDR_RESCUE_BOOT_SECTOR_SHA2 : IDR_BOOT_SECTOR_SHA2; + bootLoaderId = rescueDisk ? IDR_RESCUE_LOADER_SHA2 : IDR_BOOT_LOADER_SHA2; + } + else + { + bootSectorId = rescueDisk ? IDR_RESCUE_BOOT_SECTOR : IDR_BOOT_SECTOR; + bootLoaderId = rescueDisk ? IDR_RESCUE_LOADER : IDR_BOOT_LOADER; + } + + switch (ea) + { + case AES: + if (pkcs5_prf == SHA256) + { + bootSectorId = rescueDisk ? IDR_RESCUE_BOOT_SECTOR_AES_SHA2 : IDR_BOOT_SECTOR_AES_SHA2; + bootLoaderId = rescueDisk ? IDR_RESCUE_LOADER_AES_SHA2 : IDR_BOOT_LOADER_AES_SHA2; + } + else + { + bootSectorId = rescueDisk ? IDR_RESCUE_BOOT_SECTOR_AES : IDR_BOOT_SECTOR_AES; + bootLoaderId = rescueDisk ? IDR_RESCUE_LOADER_AES : IDR_BOOT_LOADER_AES; + } + break; + + case SERPENT: + if (pkcs5_prf == SHA256) + { + bootSectorId = rescueDisk ? IDR_RESCUE_BOOT_SECTOR_SERPENT_SHA2 : IDR_BOOT_SECTOR_SERPENT_SHA2; + bootLoaderId = rescueDisk ? IDR_RESCUE_LOADER_SERPENT_SHA2 : IDR_BOOT_LOADER_SERPENT_SHA2; + } + else + { + bootSectorId = rescueDisk ? IDR_RESCUE_BOOT_SECTOR_SERPENT : IDR_BOOT_SECTOR_SERPENT; + bootLoaderId = rescueDisk ? IDR_RESCUE_LOADER_SERPENT : IDR_BOOT_LOADER_SERPENT; + } + break; + + case TWOFISH: + if (pkcs5_prf == SHA256) + { + bootSectorId = rescueDisk ? IDR_RESCUE_BOOT_SECTOR_TWOFISH_SHA2 : IDR_BOOT_SECTOR_TWOFISH_SHA2; + bootLoaderId = rescueDisk ? IDR_RESCUE_LOADER_TWOFISH_SHA2 : IDR_BOOT_LOADER_TWOFISH_SHA2; + } + else + { + bootSectorId = rescueDisk ? IDR_RESCUE_BOOT_SECTOR_TWOFISH : IDR_BOOT_SECTOR_TWOFISH; + bootLoaderId = rescueDisk ? IDR_RESCUE_LOADER_TWOFISH : IDR_BOOT_LOADER_TWOFISH; + } + break; + } + + // Boot sector + DWORD size; + byte *bootSecResourceImg = MapResource (L"BIN", bootSectorId, &size); + if (!bootSecResourceImg || size != TC_SECTOR_SIZE_BIOS) + throw ParameterIncorrect (SRC_POS); + + memcpy (buffer, bootSecResourceImg, size); + + *(uint16 *) (buffer + TC_BOOT_SECTOR_VERSION_OFFSET) = BE16 (VERSION_NUM); + + if (IsOSAtLeast (WIN_VISTA)) + buffer[TC_BOOT_SECTOR_CONFIG_OFFSET] |= TC_BOOT_CFG_FLAG_WINDOWS_VISTA_OR_LATER; + + if (rescueDisk && (ReadDriverConfigurationFlags() & TC_DRIVER_CONFIG_DISABLE_HARDWARE_ENCRYPTION)) + buffer[TC_BOOT_SECTOR_CONFIG_OFFSET] |= TC_BOOT_CFG_FLAG_RESCUE_DISABLE_HW_ENCRYPTION; + + // Checksum of the backup header of the outer volume for the hidden system + if (hiddenOSCreation) + { + Device device (GetSystemDriveConfiguration().DevicePath); + device.CheckOpened (SRC_POS); + byte headerSector[TC_SECTOR_SIZE_BIOS]; + + device.SeekAt (HiddenOSCandidatePartition.Info.StartingOffset.QuadPart + HiddenOSCandidatePartition.Info.PartitionLength.QuadPart - TC_VOLUME_HEADER_GROUP_SIZE + TC_VOLUME_HEADER_EFFECTIVE_SIZE); + device.Read (headerSector, sizeof (headerSector)); + + *(uint32 *) (buffer + TC_BOOT_SECTOR_OUTER_VOLUME_BAK_HEADER_CRC_OFFSET) = GetCrc32 (headerSector, sizeof (headerSector)); + } + + // Decompressor + byte *decompressor = MapResource (L"BIN", IDR_BOOT_LOADER_DECOMPRESSOR, &size); + if (!decompressor || size > TC_BOOT_LOADER_DECOMPRESSOR_SECTOR_COUNT * TC_SECTOR_SIZE_BIOS) + throw ParameterIncorrect (SRC_POS); + + memcpy (buffer + TC_SECTOR_SIZE_BIOS, decompressor, size); + + // Compressed boot loader + byte *bootLoader = MapResource (L"BIN", bootLoaderId, &size); + if (!bootLoader || size > TC_MAX_BOOT_LOADER_SECTOR_COUNT * TC_SECTOR_SIZE_BIOS) + throw ParameterIncorrect (SRC_POS); + + memcpy (buffer + TC_SECTOR_SIZE_BIOS + TC_BOOT_LOADER_DECOMPRESSOR_SECTOR_COUNT * TC_SECTOR_SIZE_BIOS, bootLoader, size); + + // Boot loader and decompressor checksum + *(uint16 *) (buffer + TC_BOOT_SECTOR_LOADER_LENGTH_OFFSET) = static_cast <uint16> (size); + *(uint32 *) (buffer + TC_BOOT_SECTOR_LOADER_CHECKSUM_OFFSET) = GetChecksum (buffer + TC_SECTOR_SIZE_BIOS, + TC_BOOT_LOADER_DECOMPRESSOR_SECTOR_COUNT * TC_SECTOR_SIZE_BIOS + size); + + // Backup of decompressor and boot loader + if (size + TC_BOOT_LOADER_DECOMPRESSOR_SECTOR_COUNT * TC_SECTOR_SIZE_BIOS <= TC_BOOT_LOADER_BACKUP_SECTOR_COUNT * TC_SECTOR_SIZE_BIOS) + { + memcpy (buffer + TC_SECTOR_SIZE_BIOS + TC_BOOT_LOADER_BACKUP_SECTOR_COUNT * TC_SECTOR_SIZE_BIOS, + buffer + TC_SECTOR_SIZE_BIOS, TC_BOOT_LOADER_BACKUP_SECTOR_COUNT * TC_SECTOR_SIZE_BIOS); + + buffer[TC_BOOT_SECTOR_CONFIG_OFFSET] |= TC_BOOT_CFG_FLAG_BACKUP_LOADER_AVAILABLE; + } + else if (!rescueDisk && bootLoaderId != IDR_BOOT_LOADER && bootLoaderId != IDR_BOOT_LOADER_SHA2) + { + throw ParameterIncorrect (SRC_POS); + } + } + + + void BootEncryption::ReadBootSectorConfig (byte *config, size_t bufLength, byte *userConfig, string *customUserMessage, uint16 *bootLoaderVersion) + { + if (config && bufLength < TC_BOOT_CFG_FLAG_AREA_SIZE) + throw ParameterIncorrect (SRC_POS); + + GetSystemDriveConfigurationRequest request; + StringCchCopyW (request.DevicePath, ARRAYSIZE (request.DevicePath), GetSystemDriveConfiguration().DeviceKernelPath.c_str()); + + try + { + CallDriver (TC_IOCTL_GET_SYSTEM_DRIVE_CONFIG, &request, sizeof (request), &request, sizeof (request)); + if (config) + *config = request.Configuration; + + if (userConfig) + *userConfig = request.UserConfiguration; + + if (customUserMessage) + { + request.CustomUserMessage[TC_BOOT_SECTOR_USER_MESSAGE_MAX_LENGTH] = 0; + *customUserMessage = request.CustomUserMessage; + } + + if (bootLoaderVersion) + *bootLoaderVersion = request.BootLoaderVersion; + } + catch (...) + { + if (config) + *config = 0; + + if (userConfig) + *userConfig = 0; + + if (customUserMessage) + customUserMessage->clear(); + + if (bootLoaderVersion) + *bootLoaderVersion = 0; + } + } + + + void BootEncryption::WriteBootSectorConfig (const byte newConfig[]) + { + Device device (GetSystemDriveConfiguration().DevicePath); + device.CheckOpened (SRC_POS); + byte mbr[TC_SECTOR_SIZE_BIOS]; + + device.SeekAt (0); + device.Read (mbr, sizeof (mbr)); + + memcpy (mbr + TC_BOOT_SECTOR_CONFIG_OFFSET, newConfig, TC_BOOT_CFG_FLAG_AREA_SIZE); + + device.SeekAt (0); + device.Write (mbr, sizeof (mbr)); + + byte mbrVerificationBuf[TC_SECTOR_SIZE_BIOS]; + device.SeekAt (0); + device.Read (mbrVerificationBuf, sizeof (mbr)); + + if (memcmp (mbr, mbrVerificationBuf, sizeof (mbr)) != 0) + throw ErrorException ("ERROR_MBR_PROTECTED", SRC_POS); + } + + + void BootEncryption::WriteBootSectorUserConfig (byte userConfig, const string &customUserMessage, int pim) + { + Device device (GetSystemDriveConfiguration().DevicePath); + device.CheckOpened (SRC_POS); + byte mbr[TC_SECTOR_SIZE_BIOS]; + + device.SeekAt (0); + device.Read (mbr, sizeof (mbr)); + + if (!BufferContainsString (mbr, sizeof (mbr), TC_APP_NAME) + || BE16 (*(uint16 *) (mbr + TC_BOOT_SECTOR_VERSION_OFFSET)) != VERSION_NUM) + { + return; + } + + mbr[TC_BOOT_SECTOR_USER_CONFIG_OFFSET] = userConfig; + + memset (mbr + TC_BOOT_SECTOR_USER_MESSAGE_OFFSET, 0, TC_BOOT_SECTOR_USER_MESSAGE_MAX_LENGTH); + + if (!customUserMessage.empty()) + { + if (customUserMessage.size() > TC_BOOT_SECTOR_USER_MESSAGE_MAX_LENGTH) + throw ParameterIncorrect (SRC_POS); + + memcpy (mbr + TC_BOOT_SECTOR_USER_MESSAGE_OFFSET, customUserMessage.c_str(), customUserMessage.size()); + } + + if (userConfig & TC_BOOT_USER_CFG_FLAG_DISABLE_PIM) + { + // PIM for pre-boot authentication can be encoded on two bytes since its maximum + // value is 65535 (0xFFFF) + memcpy (mbr + TC_BOOT_SECTOR_PIM_VALUE_OFFSET, &pim, TC_BOOT_SECTOR_PIM_VALUE_SIZE); + } + else + memset (mbr + TC_BOOT_SECTOR_PIM_VALUE_OFFSET, 0, TC_BOOT_SECTOR_PIM_VALUE_SIZE); + + device.SeekAt (0); + device.Write (mbr, sizeof (mbr)); + + byte mbrVerificationBuf[TC_SECTOR_SIZE_BIOS]; + device.SeekAt (0); + device.Read (mbrVerificationBuf, sizeof (mbr)); + + if (memcmp (mbr, mbrVerificationBuf, sizeof (mbr)) != 0) + throw ErrorException ("ERROR_MBR_PROTECTED", SRC_POS); + } + + + unsigned int BootEncryption::GetHiddenOSCreationPhase () + { + byte configFlags [TC_BOOT_CFG_FLAG_AREA_SIZE]; + + ReadBootSectorConfig (configFlags, sizeof(configFlags)); + + return (configFlags[0] & TC_BOOT_CFG_MASK_HIDDEN_OS_CREATION_PHASE); + } + + + void BootEncryption::SetHiddenOSCreationPhase (unsigned int newPhase) + { +#if TC_BOOT_CFG_FLAG_AREA_SIZE != 1 +# error TC_BOOT_CFG_FLAG_AREA_SIZE != 1; revise GetHiddenOSCreationPhase() and SetHiddenOSCreationPhase() +#endif + byte configFlags [TC_BOOT_CFG_FLAG_AREA_SIZE]; + + ReadBootSectorConfig (configFlags, sizeof(configFlags)); + + configFlags[0] &= (byte) ~TC_BOOT_CFG_MASK_HIDDEN_OS_CREATION_PHASE; + + configFlags[0] |= newPhase; + + WriteBootSectorConfig (configFlags); + } + + +#ifndef SETUP + + void BootEncryption::StartDecoyOSWipe (WipeAlgorithmId wipeAlgorithm) + { + if (!IsHiddenOSRunning()) + throw ParameterIncorrect (SRC_POS); + + WipeDecoySystemRequest request; + ZeroMemory (&request, sizeof (request)); + + request.WipeAlgorithm = wipeAlgorithm; + + if (Randinit() != ERR_SUCCESS) + { + if (CryptoAPILastError == ERROR_SUCCESS) + throw RandInitFailed (SRC_POS, GetLastError ()); + else + throw CryptoApiFailed (SRC_POS, CryptoAPILastError); + } + + /* force the display of the random enriching dialog */ + SetRandomPoolEnrichedByUserStatus (FALSE); + + UserEnrichRandomPool (ParentWindow); + + if (!RandgetBytes (ParentWindow, request.WipeKey, sizeof (request.WipeKey), TRUE)) + throw ParameterIncorrect (SRC_POS); + + CallDriver (TC_IOCTL_START_DECOY_SYSTEM_WIPE, &request, sizeof (request), NULL, 0); + + burn (&request, sizeof (request)); + } + + + void BootEncryption::AbortDecoyOSWipe () + { + CallDriver (TC_IOCTL_ABORT_DECOY_SYSTEM_WIPE); + } + + + DecoySystemWipeStatus BootEncryption::GetDecoyOSWipeStatus () + { + DecoySystemWipeStatus status; + CallDriver (TC_IOCTL_GET_DECOY_SYSTEM_WIPE_STATUS, NULL, 0, &status, sizeof (status)); + return status; + } + + + void BootEncryption::CheckDecoyOSWipeResult () + { + CallDriver (TC_IOCTL_GET_DECOY_SYSTEM_WIPE_RESULT); + } + + + void BootEncryption::WipeHiddenOSCreationConfig () + { + if (IsHiddenOSRunning()) + throw ParameterIncorrect (SRC_POS); + + if (Randinit() != ERR_SUCCESS) + { + if (CryptoAPILastError == ERROR_SUCCESS) + throw RandInitFailed (SRC_POS, GetLastError ()); + else + throw CryptoApiFailed (SRC_POS, CryptoAPILastError); + } + + Device device (GetSystemDriveConfiguration().DevicePath); + device.CheckOpened(SRC_POS); + byte mbr[TC_SECTOR_SIZE_BIOS]; + + device.SeekAt (0); + device.Read (mbr, sizeof (mbr)); + + finally_do_arg (BootEncryption *, this, + { + try + { + finally_arg->SetHiddenOSCreationPhase (TC_HIDDEN_OS_CREATION_PHASE_NONE); + } catch (...) { } + }); + +#if PRAND_DISK_WIPE_PASSES > RNG_POOL_SIZE +# error PRAND_DISK_WIPE_PASSES > RNG_POOL_SIZE +#endif + + byte randData[PRAND_DISK_WIPE_PASSES]; + if (!RandgetBytes (ParentWindow, randData, sizeof (randData), FALSE)) + throw ParameterIncorrect (SRC_POS); + + for (int wipePass = 0; wipePass < PRAND_DISK_WIPE_PASSES; wipePass++) + { + for (int i = 0; i < TC_BOOT_SECTOR_OUTER_VOLUME_BAK_HEADER_CRC_SIZE; ++i) + { + mbr[TC_BOOT_SECTOR_OUTER_VOLUME_BAK_HEADER_CRC_OFFSET + i] = randData[wipePass]; + } + + mbr[TC_BOOT_SECTOR_CONFIG_OFFSET] &= (byte) ~TC_BOOT_CFG_MASK_HIDDEN_OS_CREATION_PHASE; + mbr[TC_BOOT_SECTOR_CONFIG_OFFSET] |= randData[wipePass] & TC_BOOT_CFG_MASK_HIDDEN_OS_CREATION_PHASE; + + if (wipePass == PRAND_DISK_WIPE_PASSES - 1) + memset (mbr + TC_BOOT_SECTOR_OUTER_VOLUME_BAK_HEADER_CRC_OFFSET, 0, TC_BOOT_SECTOR_OUTER_VOLUME_BAK_HEADER_CRC_SIZE); + + device.SeekAt (0); + device.Write (mbr, sizeof (mbr)); + } + + for (int wipePass = 0; wipePass < PRAND_DISK_WIPE_PASSES/4 + 1; wipePass++) + { + SetHiddenOSCreationPhase (TC_HIDDEN_OS_CREATION_PHASE_NONE); + SetHiddenOSCreationPhase (TC_HIDDEN_OS_CREATION_PHASE_CLONING); + SetHiddenOSCreationPhase (TC_HIDDEN_OS_CREATION_PHASE_WIPING); + SetHiddenOSCreationPhase (TC_HIDDEN_OS_CREATION_PHASE_WIPED); + } + SetHiddenOSCreationPhase (TC_HIDDEN_OS_CREATION_PHASE_NONE); + } + +#endif // !SETUP + + + void BootEncryption::InstallBootLoader (bool preserveUserConfig, bool hiddenOSCreation) + { + Device device (GetSystemDriveConfiguration().DevicePath); + device.CheckOpened (SRC_POS); + + InstallBootLoader (device, preserveUserConfig, hiddenOSCreation); + } + + void BootEncryption::InstallBootLoader (Device& device, bool preserveUserConfig, bool hiddenOSCreation, int pim) + { + byte bootLoaderBuf[TC_BOOT_LOADER_AREA_SIZE - TC_BOOT_ENCRYPTION_VOLUME_HEADER_SIZE] = {0}; + CreateBootLoaderInMemory (bootLoaderBuf, sizeof (bootLoaderBuf), false, hiddenOSCreation); + + // Write MBR + byte mbr[TC_SECTOR_SIZE_BIOS]; + + device.SeekAt (0); + device.Read (mbr, sizeof (mbr)); + + if (preserveUserConfig && BufferContainsString (mbr, sizeof (mbr), TC_APP_NAME)) + { + uint16 version = BE16 (*(uint16 *) (mbr + TC_BOOT_SECTOR_VERSION_OFFSET)); + if (version != 0) + { + bootLoaderBuf[TC_BOOT_SECTOR_USER_CONFIG_OFFSET] = mbr[TC_BOOT_SECTOR_USER_CONFIG_OFFSET]; + memcpy (bootLoaderBuf + TC_BOOT_SECTOR_USER_MESSAGE_OFFSET, mbr + TC_BOOT_SECTOR_USER_MESSAGE_OFFSET, TC_BOOT_SECTOR_USER_MESSAGE_MAX_LENGTH); + + if (bootLoaderBuf[TC_BOOT_SECTOR_USER_CONFIG_OFFSET] & TC_BOOT_USER_CFG_FLAG_DISABLE_PIM) + { + if (pim >= 0) + { + memcpy (bootLoaderBuf + TC_BOOT_SECTOR_PIM_VALUE_OFFSET, &pim, TC_BOOT_SECTOR_PIM_VALUE_SIZE); + } + else + memcpy (bootLoaderBuf + TC_BOOT_SECTOR_PIM_VALUE_OFFSET, mbr + TC_BOOT_SECTOR_PIM_VALUE_OFFSET, TC_BOOT_SECTOR_PIM_VALUE_SIZE); + } + } + } + + memcpy (mbr, bootLoaderBuf, TC_MAX_MBR_BOOT_CODE_SIZE); + + device.SeekAt (0); + device.Write (mbr, sizeof (mbr)); + + byte mbrVerificationBuf[TC_SECTOR_SIZE_BIOS]; + device.SeekAt (0); + device.Read (mbrVerificationBuf, sizeof (mbr)); + + if (memcmp (mbr, mbrVerificationBuf, sizeof (mbr)) != 0) + throw ErrorException ("ERROR_MBR_PROTECTED", SRC_POS); + + // Write boot loader + device.SeekAt (TC_SECTOR_SIZE_BIOS); + device.Write (bootLoaderBuf + TC_SECTOR_SIZE_BIOS, sizeof (bootLoaderBuf) - TC_SECTOR_SIZE_BIOS); + } + +#ifndef SETUP + bool BootEncryption::CheckBootloaderFingerprint (bool bSilent) + { + byte bootLoaderBuf[TC_BOOT_LOADER_AREA_SIZE - TC_BOOT_ENCRYPTION_VOLUME_HEADER_SIZE] = {0}; + byte fingerprint[WHIRLPOOL_DIGESTSIZE + SHA512_DIGESTSIZE]; + byte expectedFingerprint[WHIRLPOOL_DIGESTSIZE + SHA512_DIGESTSIZE]; + bool bRet = false; + + try + { + // read bootloader fingerprint + GetInstalledBootLoaderFingerprint (fingerprint); + + // compute expected fingerprint + CreateBootLoaderInMemory (bootLoaderBuf, sizeof (bootLoaderBuf), false, false); + ::ComputeBootloaderFingerprint (bootLoaderBuf, sizeof (bootLoaderBuf), expectedFingerprint); + + // compare values + if (0 == memcmp (fingerprint, expectedFingerprint, sizeof (expectedFingerprint))) + { + bRet = true; + } + } + catch (SystemException &e) + { + if (!bSilent && (GetLastError () != ERROR_INVALID_IMAGE_HASH)) + e.Show (ParentWindow); + } + catch (Exception& e) + { + if (!bSilent) + e.Show (ParentWindow); + } + + return bRet; + } +#endif + + wstring BootEncryption::GetSystemLoaderBackupPath () + { + WCHAR pathBuf[MAX_PATH]; + + throw_sys_if (!SUCCEEDED (SHGetFolderPath (NULL, CSIDL_COMMON_APPDATA | CSIDL_FLAG_CREATE, NULL, 0, pathBuf))); + + wstring path = wstring (pathBuf) + L"\\" _T(TC_APP_NAME); + CreateDirectory (path.c_str(), NULL); + + return path + L'\\' + TC_SYS_BOOT_LOADER_BACKUP_NAME; + } + + + void BootEncryption::RenameDeprecatedSystemLoaderBackup () + { + WCHAR pathBuf[MAX_PATH]; + + if (SUCCEEDED (SHGetFolderPath (NULL, CSIDL_COMMON_APPDATA, NULL, 0, pathBuf))) + { + wstring path = wstring (pathBuf) + L"\\" _T(TC_APP_NAME) + L'\\' + TC_SYS_BOOT_LOADER_BACKUP_NAME_LEGACY; + + if (FileExists (path.c_str()) && !FileExists (GetSystemLoaderBackupPath().c_str())) + throw_sys_if (_wrename (path.c_str(), GetSystemLoaderBackupPath().c_str()) != 0); + } + } + + +#ifndef SETUP + void BootEncryption::CreateRescueIsoImage (bool initialSetup, const wstring &isoImagePath) + { + BootEncryptionStatus encStatus = GetStatus(); + if (encStatus.SetupInProgress) + throw ParameterIncorrect (SRC_POS); + + Buffer imageBuf (RescueIsoImageSize); + + byte *image = imageBuf.Ptr(); + memset (image, 0, RescueIsoImageSize); + + // Primary volume descriptor + const char* szPrimVolDesc = "\001CD001\001"; + const char* szPrimVolLabel = "VeraCrypt Rescue Disk "; + memcpy (image + 0x8000, szPrimVolDesc, strlen(szPrimVolDesc) + 1); + memcpy (image + 0x7fff + 41, szPrimVolLabel, strlen(szPrimVolLabel) + 1); + *(uint32 *) (image + 0x7fff + 81) = RescueIsoImageSize / 2048; + *(uint32 *) (image + 0x7fff + 85) = BE32 (RescueIsoImageSize / 2048); + image[0x7fff + 121] = 1; + image[0x7fff + 124] = 1; + image[0x7fff + 125] = 1; + image[0x7fff + 128] = 1; + image[0x7fff + 130] = 8; + image[0x7fff + 131] = 8; + + image[0x7fff + 133] = 10; + image[0x7fff + 140] = 10; + image[0x7fff + 141] = 0x14; + image[0x7fff + 157] = 0x22; + image[0x7fff + 159] = 0x18; + + // Boot record volume descriptor + const char* szBootRecDesc = "CD001\001EL TORITO SPECIFICATION"; + memcpy (image + 0x8801, szBootRecDesc, strlen(szBootRecDesc) + 1); + image[0x8800 + 0x47] = 0x19; + + // Volume descriptor set terminator + const char* szVolDescTerm = "\377CD001\001"; + memcpy (image + 0x9000, szVolDescTerm, strlen(szVolDescTerm) + 1); + + // Path table + image[0xA000 + 0] = 1; + image[0xA000 + 2] = 0x18; + image[0xA000 + 6] = 1; + + // Root directory + image[0xc000 + 0] = 0x22; + image[0xc000 + 2] = 0x18; + image[0xc000 + 9] = 0x18; + image[0xc000 + 11] = 0x08; + image[0xc000 + 16] = 0x08; + image[0xc000 + 25] = 0x02; + image[0xc000 + 28] = 0x01; + image[0xc000 + 31] = 0x01; + image[0xc000 + 32] = 0x01; + image[0xc000 + 34] = 0x22; + image[0xc000 + 36] = 0x18; + image[0xc000 + 43] = 0x18; + image[0xc000 + 45] = 0x08; + image[0xc000 + 50] = 0x08; + image[0xc000 + 59] = 0x02; + image[0xc000 + 62] = 0x01; + *(uint32 *) (image + 0xc000 + 65) = 0x010101; + + // Validation entry + image[0xc800] = 1; + int offset = 0xc800 + 0x1c; + image[offset++] = 0xaa; + image[offset++] = 0x55; + image[offset++] = 0x55; + image[offset] = 0xaa; + + // Initial entry + offset = 0xc820; + image[offset++] = 0x88; + image[offset++] = 2; + image[0xc820 + 6] = 1; + image[0xc820 + 8] = TC_CD_BOOT_LOADER_SECTOR; + + // TrueCrypt Boot Loader + CreateBootLoaderInMemory (image + TC_CD_BOOTSECTOR_OFFSET, TC_BOOT_LOADER_AREA_SIZE, true); + + // Volume header + if (initialSetup) + { + if (!RescueVolumeHeaderValid) + throw ParameterIncorrect (SRC_POS); + + memcpy (image + TC_CD_BOOTSECTOR_OFFSET + TC_BOOT_VOLUME_HEADER_SECTOR_OFFSET, RescueVolumeHeader, TC_BOOT_ENCRYPTION_VOLUME_HEADER_SIZE); + } + else + { + Device bootDevice (GetSystemDriveConfiguration().DevicePath, true); + bootDevice.CheckOpened (SRC_POS); + bootDevice.SeekAt (TC_BOOT_VOLUME_HEADER_SECTOR_OFFSET); + bootDevice.Read (image + TC_CD_BOOTSECTOR_OFFSET + TC_BOOT_VOLUME_HEADER_SECTOR_OFFSET, TC_BOOT_ENCRYPTION_VOLUME_HEADER_SIZE); + } + + // Original system loader + try + { + File sysBakFile (GetSystemLoaderBackupPath(), true); + sysBakFile.CheckOpened (SRC_POS); + sysBakFile.Read (image + TC_CD_BOOTSECTOR_OFFSET + TC_ORIG_BOOT_LOADER_BACKUP_SECTOR_OFFSET, TC_BOOT_LOADER_AREA_SIZE); + + image[TC_CD_BOOTSECTOR_OFFSET + TC_BOOT_SECTOR_CONFIG_OFFSET] |= TC_BOOT_CFG_FLAG_RESCUE_DISK_ORIG_SYS_LOADER; + } + catch (Exception &e) + { + e.Show (ParentWindow); + Warning ("SYS_LOADER_UNAVAILABLE_FOR_RESCUE_DISK", ParentWindow); + } + + // Boot loader backup + CreateBootLoaderInMemory (image + TC_CD_BOOTSECTOR_OFFSET + TC_BOOT_LOADER_BACKUP_RESCUE_DISK_SECTOR_OFFSET, TC_BOOT_LOADER_AREA_SIZE, false); + + RescueIsoImage = new byte[RescueIsoImageSize]; + if (!RescueIsoImage) + throw bad_alloc(); + memcpy (RescueIsoImage, image, RescueIsoImageSize); + + if (!isoImagePath.empty()) + { + File isoFile (isoImagePath, false, true); + isoFile.Write (image, RescueIsoImageSize); + } + } +#endif + + + bool BootEncryption::IsCDRecorderPresent () + { + ICDBurn* pICDBurn; + BOOL bHasRecorder = FALSE; + + if (SUCCEEDED( CoCreateInstance (CLSID_CDBurn, NULL,CLSCTX_INPROC_SERVER,IID_ICDBurn,(LPVOID*)&pICDBurn))) + { + if (pICDBurn->HasRecordableDrive (&bHasRecorder) != S_OK) + { + bHasRecorder = FALSE; + } + pICDBurn->Release(); + } + return bHasRecorder? true : false; + } + + + bool BootEncryption::VerifyRescueDisk () + { + if (!RescueIsoImage) + throw ParameterIncorrect (SRC_POS); + + for (WCHAR drive = L'Z'; drive >= L'C'; --drive) + { + try + { + WCHAR rootPath[4] = { drive, L':', L'\\', 0}; + UINT driveType = GetDriveType (rootPath); + // check that it is a CD/DVD drive or a removable media in case a bootable + // USB key was created from the rescue disk ISO file + if ((DRIVE_CDROM == driveType) || (DRIVE_REMOVABLE == driveType)) + { + rootPath[2] = 0; // remove trailing backslash + + Device driveDevice (rootPath, true); + driveDevice.CheckOpened (SRC_POS); + size_t verifiedSectorCount = (TC_CD_BOOTSECTOR_OFFSET + TC_ORIG_BOOT_LOADER_BACKUP_SECTOR_OFFSET + TC_BOOT_LOADER_AREA_SIZE) / 2048; + Buffer buffer ((verifiedSectorCount + 1) * 2048); + + DWORD bytesRead = driveDevice.Read (buffer.Ptr(), (DWORD) buffer.Size()); + if (bytesRead != buffer.Size()) + continue; + + if (memcmp (buffer.Ptr(), RescueIsoImage, buffer.Size()) == 0) + return true; + } + } + catch (...) { } + } + + return false; + } + + bool BootEncryption::VerifyRescueDiskIsoImage (const wchar_t* imageFile) + { + if (!RescueIsoImage) + throw ParameterIncorrect (SRC_POS); + + try + { + File isoFile (imageFile, true); + isoFile.CheckOpened (SRC_POS); + size_t verifiedSectorCount = (TC_CD_BOOTSECTOR_OFFSET + TC_ORIG_BOOT_LOADER_BACKUP_SECTOR_OFFSET + TC_BOOT_LOADER_AREA_SIZE) / 2048; + Buffer buffer ((verifiedSectorCount + 1) * 2048); + + DWORD bytesRead = isoFile.Read (buffer.Ptr(), (DWORD) buffer.Size()); + if ( (bytesRead == buffer.Size()) + && (memcmp (buffer.Ptr(), RescueIsoImage, buffer.Size()) == 0) + ) + { + return true; + } + } + catch (...) { } + + return false; + } + + +#ifndef SETUP + + void BootEncryption::CreateVolumeHeader (uint64 volumeSize, uint64 encryptedAreaStart, Password *password, int ea, int mode, int pkcs5, int pim) + { + PCRYPTO_INFO cryptoInfo = NULL; + + if (!IsRandomNumberGeneratorStarted()) + throw ParameterIncorrect (SRC_POS); + + throw_sys_if (CreateVolumeHeaderInMemory (ParentWindow, TRUE, (char *) VolumeHeader, ea, mode, password, pkcs5, pim, NULL, &cryptoInfo, + volumeSize, 0, encryptedAreaStart, 0, TC_SYSENC_KEYSCOPE_MIN_REQ_PROG_VERSION, TC_HEADER_FLAG_ENCRYPTED_SYSTEM, TC_SECTOR_SIZE_BIOS, FALSE) != 0); + + finally_do_arg (PCRYPTO_INFO*, &cryptoInfo, { crypto_close (*finally_arg); }); + + // Initial rescue disk assumes encryption of the drive has been completed (EncryptedAreaLength == volumeSize) + memcpy (RescueVolumeHeader, VolumeHeader, sizeof (RescueVolumeHeader)); + if (0 != ReadVolumeHeader (TRUE, (char *) RescueVolumeHeader, password, pkcs5, pim, FALSE, NULL, cryptoInfo)) + throw ParameterIncorrect (SRC_POS); + + DecryptBuffer (RescueVolumeHeader + HEADER_ENCRYPTED_DATA_OFFSET, HEADER_ENCRYPTED_DATA_SIZE, cryptoInfo); + + if (GetHeaderField32 (RescueVolumeHeader, TC_HEADER_OFFSET_MAGIC) != 0x56455241) + throw ParameterIncorrect (SRC_POS); + + byte *fieldPos = RescueVolumeHeader + TC_HEADER_OFFSET_ENCRYPTED_AREA_LENGTH; + mputInt64 (fieldPos, volumeSize); + + // CRC of the header fields + uint32 crc = GetCrc32 (RescueVolumeHeader + TC_HEADER_OFFSET_MAGIC, TC_HEADER_OFFSET_HEADER_CRC - TC_HEADER_OFFSET_MAGIC); + fieldPos = RescueVolumeHeader + TC_HEADER_OFFSET_HEADER_CRC; + mputLong (fieldPos, crc); + + EncryptBuffer (RescueVolumeHeader + HEADER_ENCRYPTED_DATA_OFFSET, HEADER_ENCRYPTED_DATA_SIZE, cryptoInfo); + + VolumeHeaderValid = true; + RescueVolumeHeaderValid = true; + } + + + void BootEncryption::InstallVolumeHeader () + { + if (!VolumeHeaderValid) + throw ParameterIncorrect (SRC_POS); + + Device device (GetSystemDriveConfiguration().DevicePath); + device.CheckOpened (SRC_POS); + + device.SeekAt (TC_BOOT_VOLUME_HEADER_SECTOR_OFFSET); + device.Write ((byte *) VolumeHeader, sizeof (VolumeHeader)); + } + + + // For synchronous operations use AbortSetupWait() + void BootEncryption::AbortSetup () + { + CallDriver (TC_IOCTL_ABORT_BOOT_ENCRYPTION_SETUP); + } + + + // For asynchronous operations use AbortSetup() + void BootEncryption::AbortSetupWait () + { + CallDriver (TC_IOCTL_ABORT_BOOT_ENCRYPTION_SETUP); + + BootEncryptionStatus encStatus = GetStatus(); + + while (encStatus.SetupInProgress) + { + Sleep (TC_ABORT_TRANSFORM_WAIT_INTERVAL); + encStatus = GetStatus(); + } + } + + + void BootEncryption::BackupSystemLoader () + { + Device device (GetSystemDriveConfiguration().DevicePath, true); + device.CheckOpened (SRC_POS); + byte bootLoaderBuf[TC_BOOT_LOADER_AREA_SECTOR_COUNT * TC_SECTOR_SIZE_BIOS]; + + device.SeekAt (0); + device.Read (bootLoaderBuf, sizeof (bootLoaderBuf)); + + // Prevent TrueCrypt loader from being backed up + for (size_t i = 0; i < sizeof (bootLoaderBuf) - strlen (TC_APP_NAME); ++i) + { + if (memcmp (bootLoaderBuf + i, TC_APP_NAME, strlen (TC_APP_NAME)) == 0) + { + if (AskWarnNoYes ("TC_BOOT_LOADER_ALREADY_INSTALLED", ParentWindow) == IDNO) + throw UserAbort (SRC_POS); + return; + } + } + + File backupFile (GetSystemLoaderBackupPath(), false, true); + backupFile.Write (bootLoaderBuf, sizeof (bootLoaderBuf)); + } + + + void BootEncryption::RestoreSystemLoader () + { + byte bootLoaderBuf[TC_BOOT_LOADER_AREA_SECTOR_COUNT * TC_SECTOR_SIZE_BIOS]; + + File backupFile (GetSystemLoaderBackupPath(), true); + backupFile.CheckOpened(SRC_POS); + if (backupFile.Read (bootLoaderBuf, sizeof (bootLoaderBuf)) != sizeof (bootLoaderBuf)) + throw ParameterIncorrect (SRC_POS); + + Device device (GetSystemDriveConfiguration().DevicePath); + device.CheckOpened (SRC_POS); + + // Preserve current partition table + byte mbr[TC_SECTOR_SIZE_BIOS]; + device.SeekAt (0); + device.Read (mbr, sizeof (mbr)); + memcpy (bootLoaderBuf + TC_MAX_MBR_BOOT_CODE_SIZE, mbr + TC_MAX_MBR_BOOT_CODE_SIZE, sizeof (mbr) - TC_MAX_MBR_BOOT_CODE_SIZE); + + device.SeekAt (0); + device.Write (bootLoaderBuf, sizeof (bootLoaderBuf)); + } + +#endif // SETUP + + void BootEncryption::RegisterFilter (bool registerFilter, FilterType filterType, const GUID *deviceClassGuid) + { + string filter; + string filterReg; + HKEY regKey; + + switch (filterType) + { + case DriveFilter: + case VolumeFilter: + filter = "veracrypt"; + filterReg = "UpperFilters"; + regKey = OpenDeviceClassRegKey (deviceClassGuid); + throw_sys_if (regKey == INVALID_HANDLE_VALUE); + + break; + + case DumpFilter: + if (!IsOSAtLeast (WIN_VISTA)) + return; + + filter = "veracrypt.sys"; + filterReg = "DumpFilters"; + SetLastError (RegOpenKeyEx (HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Control\\CrashControl", 0, KEY_READ | KEY_WRITE, ®Key)); + throw_sys_if (GetLastError() != ERROR_SUCCESS); + + break; + + default: + throw ParameterIncorrect (SRC_POS); + } + + finally_do_arg (HKEY, regKey, { RegCloseKey (finally_arg); }); + + if (registerFilter && filterType != DumpFilter) + { + // Register class filter below all other filters in the stack + + size_t strSize = filter.size() + 1; + byte regKeyBuf[65536]; + DWORD size = (DWORD) (sizeof (regKeyBuf) - strSize); + + // SetupInstallFromInfSection() does not support prepending of values so we have to modify the registry directly + StringCchCopyA ((char *) regKeyBuf, ARRAYSIZE(regKeyBuf), filter.c_str()); + + if (RegQueryValueExA (regKey, filterReg.c_str(), NULL, NULL, regKeyBuf + strSize, &size) != ERROR_SUCCESS) + size = 1; + + SetLastError (RegSetValueExA (regKey, filterReg.c_str(), 0, REG_MULTI_SZ, regKeyBuf, (DWORD) strSize + size)); + throw_sys_if (GetLastError() != ERROR_SUCCESS); + } + else + { + RegisterDriverInf (registerFilter, filter, filterReg, ParentWindow, regKey); + } + } + + void BootEncryption::RegisterFilterDriver (bool registerDriver, FilterType filterType) + { + if (!IsAdmin() && IsUacSupported()) + { + Elevator::RegisterFilterDriver (registerDriver, filterType); + return; + } + + switch (filterType) + { + case DriveFilter: + RegisterFilter (registerDriver, filterType, &GUID_DEVCLASS_DISKDRIVE); + break; + + case VolumeFilter: + RegisterFilter (registerDriver, filterType, &GUID_DEVCLASS_VOLUME); + RegisterFilter (registerDriver, filterType, &GUID_DEVCLASS_FLOPPYDISK); + break; + + case DumpFilter: + RegisterFilter (registerDriver, filterType); + break; + + default: + throw ParameterIncorrect (SRC_POS); + } + } + + void BootEncryption::RegisterSystemFavoritesService (BOOL registerService, BOOL noFileHandling) + { + SC_HANDLE scm = OpenSCManager (NULL, NULL, SC_MANAGER_ALL_ACCESS); + throw_sys_if (!scm); + finally_do_arg (SC_HANDLE, scm, { CloseServiceHandle (finally_arg); }); + + wstring servicePath = GetServiceConfigPath (_T(TC_APP_NAME) L".exe", false); + wstring serviceLegacyPath = GetServiceConfigPath (_T(TC_APP_NAME) L".exe", true); + + if (registerService) + { + try + { + RegisterSystemFavoritesService (FALSE, noFileHandling); + } + catch (...) { } + + if (!noFileHandling) + { + wchar_t appPath[TC_MAX_PATH]; + throw_sys_if (!GetModuleFileName (NULL, appPath, ARRAYSIZE (appPath))); + + throw_sys_if (!CopyFile (appPath, servicePath.c_str(), FALSE)); + } + + SC_HANDLE service = CreateService (scm, + TC_SYSTEM_FAVORITES_SERVICE_NAME, + _T(TC_APP_NAME) L" System Favorites", + SERVICE_ALL_ACCESS, + SERVICE_WIN32_OWN_PROCESS, + SERVICE_AUTO_START, + SERVICE_ERROR_NORMAL, + (wstring (L"\"") + servicePath + L"\" " TC_SYSTEM_FAVORITES_SERVICE_CMDLINE_OPTION).c_str(), + TC_SYSTEM_FAVORITES_SERVICE_LOAD_ORDER_GROUP, + NULL, + NULL, + NULL, + NULL); + + throw_sys_if (!service); + + SERVICE_DESCRIPTION description; + description.lpDescription = L"Mounts VeraCrypt system favorite volumes."; + ChangeServiceConfig2 (service, SERVICE_CONFIG_DESCRIPTION, &description); + + CloseServiceHandle (service); + + try + { + WriteLocalMachineRegistryString (L"SYSTEM\\CurrentControlSet\\Control\\SafeBoot\\Minimal\\" TC_SYSTEM_FAVORITES_SERVICE_NAME, NULL, L"Service", FALSE); + WriteLocalMachineRegistryString (L"SYSTEM\\CurrentControlSet\\Control\\SafeBoot\\Network\\" TC_SYSTEM_FAVORITES_SERVICE_NAME, NULL, L"Service", FALSE); + + SetDriverConfigurationFlag (TC_DRIVER_CONFIG_CACHE_BOOT_PASSWORD_FOR_SYS_FAVORITES, true); + } + catch (...) + { + try + { + RegisterSystemFavoritesService (FALSE, noFileHandling); + } + catch (...) { } + + throw; + } + } + else + { + SetDriverConfigurationFlag (TC_DRIVER_CONFIG_CACHE_BOOT_PASSWORD_FOR_SYS_FAVORITES, false); + + DeleteLocalMachineRegistryKey (L"SYSTEM\\CurrentControlSet\\Control\\SafeBoot\\Minimal", TC_SYSTEM_FAVORITES_SERVICE_NAME); + DeleteLocalMachineRegistryKey (L"SYSTEM\\CurrentControlSet\\Control\\SafeBoot\\Network", TC_SYSTEM_FAVORITES_SERVICE_NAME); + + SC_HANDLE service = OpenService (scm, TC_SYSTEM_FAVORITES_SERVICE_NAME, SERVICE_ALL_ACCESS); + throw_sys_if (!service); + + throw_sys_if (!DeleteService (service)); + CloseServiceHandle (service); + + if (!noFileHandling) + { + DeleteFile (servicePath.c_str()); + if (serviceLegacyPath != servicePath) + DeleteFile (serviceLegacyPath.c_str()); + } + } + } + + void BootEncryption::UpdateSystemFavoritesService () + { + SC_HANDLE scm = OpenSCManager (NULL, NULL, SC_MANAGER_ALL_ACCESS); + throw_sys_if (!scm); + + finally_do_arg (SC_HANDLE, scm, { CloseServiceHandle (finally_arg); }); + + wstring servicePath = GetServiceConfigPath (_T(TC_APP_NAME) L".exe", false); + + // check if service exists + SC_HANDLE service = OpenService (scm, TC_SYSTEM_FAVORITES_SERVICE_NAME, SERVICE_ALL_ACCESS); + if (service) + { + finally_do_arg (SC_HANDLE, service, { CloseServiceHandle (finally_arg); }); + // ensure that its parameters are correct + throw_sys_if (!ChangeServiceConfig (service, + SERVICE_WIN32_OWN_PROCESS, + SERVICE_AUTO_START, + SERVICE_ERROR_NORMAL, + (wstring (L"\"") + servicePath + L"\" " TC_SYSTEM_FAVORITES_SERVICE_CMDLINE_OPTION).c_str(), + TC_SYSTEM_FAVORITES_SERVICE_LOAD_ORDER_GROUP, + NULL, + NULL, + NULL, + NULL, + _T(TC_APP_NAME) L" System Favorites")); + + } + else + { + RegisterSystemFavoritesService (TRUE, TRUE); + } + } + + void BootEncryption::SetDriverConfigurationFlag (uint32 flag, bool state) + { + DWORD configMap = ReadDriverConfigurationFlags(); + + if (state) + configMap |= flag; + else + configMap &= ~flag; +#ifdef SETUP + WriteLocalMachineRegistryDword (L"SYSTEM\\CurrentControlSet\\Services\\veracrypt", TC_DRIVER_CONFIG_REG_VALUE_NAME, configMap); +#else + WriteLocalMachineRegistryDwordValue (L"SYSTEM\\CurrentControlSet\\Services\\veracrypt", TC_DRIVER_CONFIG_REG_VALUE_NAME, configMap); +#endif + } + +#ifndef SETUP + + void BootEncryption::RegisterSystemFavoritesService (BOOL registerService) + { + if (!IsAdmin() && IsUacSupported()) + { + Elevator::RegisterSystemFavoritesService (registerService); + return; + } + + RegisterSystemFavoritesService (registerService, FALSE); + } + + void BootEncryption::CheckRequirements () + { + if (nCurrentOS == WIN_2000) + throw ErrorException ("SYS_ENCRYPTION_UNSUPPORTED_ON_CURRENT_OS", SRC_POS); + + if (CurrentOSMajor == 6 && CurrentOSMinor == 0 && CurrentOSServicePack < 1) + throw ErrorException ("SYS_ENCRYPTION_UNSUPPORTED_ON_VISTA_SP0", SRC_POS); + + if (IsNonInstallMode()) + throw ErrorException ("FEATURE_REQUIRES_INSTALLATION", SRC_POS); + + SystemDriveConfiguration config = GetSystemDriveConfiguration (); + + if (config.SystemPartition.IsGPT) + throw ErrorException ("GPT_BOOT_DRIVE_UNSUPPORTED", SRC_POS); + + if (SystemDriveIsDynamic()) + throw ErrorException ("SYSENC_UNSUPPORTED_FOR_DYNAMIC_DISK", SRC_POS); + + if (config.InitialUnallocatedSpace < TC_BOOT_LOADER_AREA_SIZE) + throw ErrorException ("NO_SPACE_FOR_BOOT_LOADER", SRC_POS); + + DISK_GEOMETRY geometry = GetDriveGeometry (config.DriveNumber); + + if (geometry.BytesPerSector != TC_SECTOR_SIZE_BIOS) + throw ErrorException ("SYSENC_UNSUPPORTED_SECTOR_SIZE_BIOS", SRC_POS); + + bool activePartitionFound = false; + if (!config.SystemPartition.IsGPT) + { + // Determine whether there is an Active partition on the system drive + foreach (const Partition &partition, config.Partitions) + { + if (partition.Info.BootIndicator) + { + activePartitionFound = true; + break; + } + } + } + + if (!config.SystemLoaderPresent || !activePartitionFound) + { + static bool confirmed = false; + + if (!confirmed && AskWarnNoYes ("WINDOWS_NOT_ON_BOOT_DRIVE_ERROR", ParentWindow) == IDNO) + throw UserAbort (SRC_POS); + + confirmed = true; + } + } + + + void BootEncryption::CheckRequirementsHiddenOS () + { + // It is assumed that CheckRequirements() had been called (so we don't check e.g. whether it's GPT). + + // The user may have modified/added/deleted partitions since the partition table was last scanned. + InvalidateCachedSysDriveProperties (); + + GetPartitionForHiddenOS (); + } + + + void BootEncryption::InitialSecurityChecksForHiddenOS () + { + wchar_t windowsDrive = (wchar_t) towupper (GetWindowsDirectory()[0]); + + // Paging files + bool pagingFilesOk = !IsPagingFileActive (TRUE); + + wchar_t pagingFileRegData[65536]; + DWORD pagingFileRegDataSize = sizeof (pagingFileRegData); + + if (ReadLocalMachineRegistryMultiString (L"System\\CurrentControlSet\\Control\\Session Manager\\Memory Management", L"PagingFiles", pagingFileRegData, &pagingFileRegDataSize) + && pagingFileRegDataSize > 8) + { + for (size_t i = 1; i < pagingFileRegDataSize/2 - 2; ++i) + { + if (wmemcmp (pagingFileRegData + i, L":\\", 2) == 0 && towupper (pagingFileRegData[i - 1]) != windowsDrive) + { + pagingFilesOk = false; + break; + } + } + } + + if (!pagingFilesOk) + { + if (AskWarnYesNoString ((wchar_t *) (wstring (GetString ("PAGING_FILE_NOT_ON_SYS_PARTITION")) + + GetString ("LEAKS_OUTSIDE_SYSPART_UNIVERSAL_EXPLANATION") + + L"\n\n\n" + + GetString ("RESTRICT_PAGING_FILES_TO_SYS_PARTITION") + ).c_str(), ParentWindow) == IDYES) + { + RestrictPagingFilesToSystemPartition(); + RestartComputer(); + AbortProcessSilent(); + } + + throw ErrorException (wstring (GetString ("PAGING_FILE_NOT_ON_SYS_PARTITION")) + + GetString ("LEAKS_OUTSIDE_SYSPART_UNIVERSAL_EXPLANATION"), SRC_POS); + } + + // User profile + wchar_t *configPath = GetConfigPath (L"dummy"); + if (configPath && towupper (configPath[0]) != windowsDrive) + { + throw ErrorException (wstring (GetString ("USER_PROFILE_NOT_ON_SYS_PARTITION")) + + GetString ("LEAKS_OUTSIDE_SYSPART_UNIVERSAL_EXPLANATION"), SRC_POS); + } + + // Temporary files + if (towupper (GetTempPathString()[0]) != windowsDrive) + { + throw ErrorException (wstring (GetString ("TEMP_NOT_ON_SYS_PARTITION")) + + GetString ("LEAKS_OUTSIDE_SYSPART_UNIVERSAL_EXPLANATION"), SRC_POS); + } + } + + + // This operation may take a long time when an antivirus is installed and its real-time protection enabled. + // Therefore, if calling it without the wizard displayed, it should be called with displayWaitDialog set to true. + void BootEncryption::Deinstall (bool displayWaitDialog) + { + BootEncryptionStatus encStatus = GetStatus(); + + if (encStatus.DriveEncrypted || encStatus.DriveMounted) + throw ParameterIncorrect (SRC_POS); + + SystemDriveConfiguration config = GetSystemDriveConfiguration (); + + if (encStatus.VolumeHeaderPresent) + { + // Verify CRC of header salt + Device device (config.DevicePath, true); + device.CheckOpened (SRC_POS); + byte header[TC_BOOT_ENCRYPTION_VOLUME_HEADER_SIZE]; + + device.SeekAt (TC_BOOT_VOLUME_HEADER_SECTOR_OFFSET); + device.Read (header, sizeof (header)); + + if (encStatus.VolumeHeaderSaltCrc32 != GetCrc32 ((byte *) header, PKCS5_SALT_SIZE)) + throw ParameterIncorrect (SRC_POS); + } + + try + { + RegisterFilterDriver (false, DriveFilter); + RegisterFilterDriver (false, VolumeFilter); + RegisterFilterDriver (false, DumpFilter); + SetDriverServiceStartType (SERVICE_SYSTEM_START); + } + catch (...) + { + try + { + RegisterBootDriver (IsHiddenSystemRunning()); + } + catch (...) { } + + throw; + } + + SetHiddenOSCreationPhase (TC_HIDDEN_OS_CREATION_PHASE_NONE); // In case RestoreSystemLoader() fails + + try + { + RegisterSystemFavoritesService (false); + } + catch (...) { } + + try + { + if (displayWaitDialog) + DisplayStaticModelessWaitDlg (ParentWindow); + + finally_do_arg (bool, displayWaitDialog, { if (finally_arg) CloseStaticModelessWaitDlg(); }); + + RestoreSystemLoader (); + } + catch (Exception &e) + { + e.Show (ParentWindow); + throw ErrorException ("SYS_LOADER_RESTORE_FAILED", SRC_POS); + } + } + + + int BootEncryption::ChangePassword (Password *oldPassword, int old_pkcs5, int old_pim, Password *newPassword, int pkcs5, int pim, int wipePassCount, HWND hwndDlg) + { + BootEncryptionStatus encStatus = GetStatus(); + + if (encStatus.SetupInProgress || (wipePassCount <= 0)) + throw ParameterIncorrect (SRC_POS); + + SystemDriveConfiguration config = GetSystemDriveConfiguration (); + + char header[TC_BOOT_ENCRYPTION_VOLUME_HEADER_SIZE]; + Device device (config.DevicePath); + device.CheckOpened (SRC_POS); + + // Only one algorithm is currently supported + if (pkcs5 != 0) + throw ParameterIncorrect (SRC_POS); + + int64 headerOffset = TC_BOOT_VOLUME_HEADER_SECTOR_OFFSET; + int64 backupHeaderOffset = -1; + + if (encStatus.HiddenSystem) + { + headerOffset = encStatus.HiddenSystemPartitionStart + TC_HIDDEN_VOLUME_HEADER_OFFSET; + + // Find hidden system partition + foreach (const Partition &partition, config.Partitions) + { + if (partition.Info.StartingOffset.QuadPart == encStatus.HiddenSystemPartitionStart) + { + backupHeaderOffset = partition.Info.StartingOffset.QuadPart + partition.Info.PartitionLength.QuadPart - TC_VOLUME_HEADER_SIZE; + break; + } + } + + if (backupHeaderOffset == -1) + throw ParameterIncorrect (SRC_POS); + } + + device.SeekAt (headerOffset); + device.Read ((byte *) header, sizeof (header)); + + PCRYPTO_INFO cryptoInfo = NULL; + + int status = ReadVolumeHeader (!encStatus.HiddenSystem, header, oldPassword, old_pkcs5, old_pim, FALSE, &cryptoInfo, NULL); + finally_do_arg (PCRYPTO_INFO, cryptoInfo, { if (finally_arg) crypto_close (finally_arg); }); + + if (status != 0) + { + handleError (hwndDlg, status, SRC_POS); + return status; + } + + // Change the PKCS-5 PRF if requested by user + if (pkcs5 != 0) + { + cryptoInfo->pkcs5 = pkcs5; + RandSetHashFunction (pkcs5); + } + + if (Randinit() != 0) + { + if (CryptoAPILastError == ERROR_SUCCESS) + throw RandInitFailed (SRC_POS, GetLastError ()); + else + throw CryptoApiFailed (SRC_POS, CryptoAPILastError); + } + finally_do ({ RandStop (FALSE); }); + + /* force the display of the random enriching dialog */ + SetRandomPoolEnrichedByUserStatus (FALSE); + + NormalCursor(); + UserEnrichRandomPool (hwndDlg); + WaitCursor(); + + /* The header will be re-encrypted wipePassCount times to prevent adversaries from using + techniques such as magnetic force microscopy or magnetic force scanning tunnelling microscopy + to recover the overwritten header. According to Peter Gutmann, data should be overwritten 22 + times (ideally, 35 times) using non-random patterns and pseudorandom data. However, as users might + impatiently interupt the process (etc.) we will not use the Gutmann's patterns but will write the + valid re-encrypted header, i.e. pseudorandom data, and there will be many more passes than Guttman + recommends. During each pass we will write a valid working header. Each pass will use the same master + key, and also the same header key, secondary key (XTS), etc., derived from the new password. The only + item that will be different for each pass will be the salt. This is sufficient to cause each "version" + of the header to differ substantially and in a random manner from the versions written during the + other passes. */ + + bool headerUpdated = false; + int result = ERR_SUCCESS; + + try + { + BOOL backupHeader = FALSE; + while (TRUE) + { + for (int wipePass = 0; wipePass < wipePassCount; wipePass++) + { + PCRYPTO_INFO tmpCryptoInfo = NULL; + + status = CreateVolumeHeaderInMemory (hwndDlg, !encStatus.HiddenSystem, + header, + cryptoInfo->ea, + cryptoInfo->mode, + newPassword, + cryptoInfo->pkcs5, + pim, + (char *) cryptoInfo->master_keydata, + &tmpCryptoInfo, + cryptoInfo->VolumeSize.Value, + cryptoInfo->hiddenVolumeSize, + cryptoInfo->EncryptedAreaStart.Value, + cryptoInfo->EncryptedAreaLength.Value, + cryptoInfo->RequiredProgramVersion, + cryptoInfo->HeaderFlags | TC_HEADER_FLAG_ENCRYPTED_SYSTEM, + cryptoInfo->SectorSize, + wipePass < wipePassCount - 1); + + if (tmpCryptoInfo) + crypto_close (tmpCryptoInfo); + + if (status != 0) + { + handleError (hwndDlg, status, SRC_POS); + return status; + } + + device.SeekAt (headerOffset); + device.Write ((byte *) header, sizeof (header)); + headerUpdated = true; + } + + if (!encStatus.HiddenSystem || backupHeader) + break; + + backupHeader = TRUE; + headerOffset = backupHeaderOffset; + } + } + catch (Exception &e) + { + e.Show (hwndDlg); + result = ERR_OS_ERROR; + } + + if (headerUpdated) + { + bool storedPimUpdateNeeded = false; + ReopenBootVolumeHeaderRequest reopenRequest; + reopenRequest.VolumePassword = *newPassword; + reopenRequest.pkcs5_prf = cryptoInfo->pkcs5; + reopenRequest.pim = pim; + finally_do_arg (ReopenBootVolumeHeaderRequest*, &reopenRequest, { burn (finally_arg, sizeof (*finally_arg)); }); + + if (old_pim != pim) + { + try + { + // check if PIM is stored in MBR + byte userConfig; + ReadBootSectorConfig (nullptr, 0, &userConfig); + if (userConfig & TC_BOOT_USER_CFG_FLAG_DISABLE_PIM) + storedPimUpdateNeeded = true; + } + catch (...) + {} + } + + try + { + // force update of bootloader if fingerprint doesn't match or if the stored PIM changed + if (storedPimUpdateNeeded || !CheckBootloaderFingerprint (true)) + InstallBootLoader (device, true, false, pim); + } + catch (...) + {} + + CallDriver (TC_IOCTL_REOPEN_BOOT_VOLUME_HEADER, &reopenRequest, sizeof (reopenRequest)); + } + + return result; + } + + + void BootEncryption::CheckEncryptionSetupResult () + { + CallDriver (TC_IOCTL_GET_BOOT_ENCRYPTION_SETUP_RESULT); + } + + + void BootEncryption::Install (bool hiddenSystem) + { + BootEncryptionStatus encStatus = GetStatus(); + if (encStatus.DriveMounted) + throw ParameterIncorrect (SRC_POS); + + try + { + InstallBootLoader (false, hiddenSystem); + + if (!hiddenSystem) + InstallVolumeHeader (); + + RegisterBootDriver (hiddenSystem); + } + catch (Exception &) + { + try + { + RestoreSystemLoader (); + } + catch (Exception &e) + { + e.Show (ParentWindow); + } + + throw; + } + } + + + void BootEncryption::PrepareHiddenOSCreation (int ea, int mode, int pkcs5) + { + BootEncryptionStatus encStatus = GetStatus(); + if (encStatus.DriveMounted) + throw ParameterIncorrect (SRC_POS); + + CheckRequirements(); + BackupSystemLoader(); + + SelectedEncryptionAlgorithmId = ea; + SelectedPrfAlgorithmId = pkcs5; + } + + + void BootEncryption::PrepareInstallation (bool systemPartitionOnly, Password &password, int ea, int mode, int pkcs5, int pim, const wstring &rescueIsoImagePath) + { + BootEncryptionStatus encStatus = GetStatus(); + if (encStatus.DriveMounted) + throw ParameterIncorrect (SRC_POS); + + CheckRequirements (); + + SystemDriveConfiguration config = GetSystemDriveConfiguration(); + + // Some chipset drivers may prevent access to the last sector of the drive + if (!systemPartitionOnly) + { + DISK_GEOMETRY geometry = GetDriveGeometry (config.DriveNumber); + if ((geometry.BytesPerSector > 0) && (geometry.BytesPerSector < TC_MAX_VOLUME_SECTOR_SIZE)) + { + Buffer sector (geometry.BytesPerSector); + + Device device (config.DevicePath); + device.CheckOpened (SRC_POS); + + try + { + device.SeekAt (config.DrivePartition.Info.PartitionLength.QuadPart - geometry.BytesPerSector); + device.Read (sector.Ptr(), (DWORD) sector.Size()); + } + catch (SystemException &e) + { + if (e.ErrorCode != ERROR_CRC) + { + e.Show (ParentWindow); + Error ("WHOLE_DRIVE_ENCRYPTION_PREVENTED_BY_DRIVERS", ParentWindow); + throw UserAbort (SRC_POS); + } + } + } + } + + BackupSystemLoader (); + + uint64 volumeSize; + uint64 encryptedAreaStart; + + if (systemPartitionOnly) + { + volumeSize = config.SystemPartition.Info.PartitionLength.QuadPart; + encryptedAreaStart = config.SystemPartition.Info.StartingOffset.QuadPart; + } + else + { + volumeSize = config.DrivePartition.Info.PartitionLength.QuadPart - TC_BOOT_LOADER_AREA_SIZE; + encryptedAreaStart = config.DrivePartition.Info.StartingOffset.QuadPart + TC_BOOT_LOADER_AREA_SIZE; + } + + SelectedEncryptionAlgorithmId = ea; + SelectedPrfAlgorithmId = pkcs5; + CreateVolumeHeader (volumeSize, encryptedAreaStart, &password, ea, mode, pkcs5, pim); + + if (!rescueIsoImagePath.empty()) + CreateRescueIsoImage (true, rescueIsoImagePath); + } + + bool BootEncryption::IsPagingFileActive (BOOL checkNonWindowsPartitionsOnly) + { + if (!IsAdmin() && IsUacSupported()) + return Elevator::IsPagingFileActive (checkNonWindowsPartitionsOnly) ? true : false; + + return ::IsPagingFileActive (checkNonWindowsPartitionsOnly) ? true : false; + } + + void BootEncryption::RestrictPagingFilesToSystemPartition () + { + wchar_t pagingFiles[128] = {0}; + StringCchCopyW (pagingFiles, ARRAYSIZE(pagingFiles), L"X:\\pagefile.sys 0 0"); + pagingFiles[0] = GetWindowsDirectory()[0]; + + throw_sys_if (!WriteLocalMachineRegistryMultiString (L"System\\CurrentControlSet\\Control\\Session Manager\\Memory Management", L"PagingFiles", pagingFiles, (DWORD) (wcslen (pagingFiles) + 2) * sizeof (wchar_t))); + } + + void BootEncryption::WriteLocalMachineRegistryDwordValue (wchar_t *keyPath, wchar_t *valueName, DWORD value) + { + if (!IsAdmin() && IsUacSupported()) + { + Elevator::WriteLocalMachineRegistryDwordValue (keyPath, valueName, value); + return; + } + + throw_sys_if (!WriteLocalMachineRegistryDword (keyPath, valueName, value)); + } + + void BootEncryption::StartDecryption (BOOL discardUnreadableEncryptedSectors) + { + BootEncryptionStatus encStatus = GetStatus(); + + if (!encStatus.DeviceFilterActive || !encStatus.DriveMounted || encStatus.SetupInProgress) + throw ParameterIncorrect (SRC_POS); + + BootEncryptionSetupRequest request; + ZeroMemory (&request, sizeof (request)); + + request.SetupMode = SetupDecryption; + request.DiscardUnreadableEncryptedSectors = discardUnreadableEncryptedSectors; + + CallDriver (TC_IOCTL_BOOT_ENCRYPTION_SETUP, &request, sizeof (request), NULL, 0); + } + + void BootEncryption::StartEncryption (WipeAlgorithmId wipeAlgorithm, bool zeroUnreadableSectors) + { + BootEncryptionStatus encStatus = GetStatus(); + + if (!encStatus.DeviceFilterActive || !encStatus.DriveMounted || encStatus.SetupInProgress) + throw ParameterIncorrect (SRC_POS); + + BootEncryptionSetupRequest request; + ZeroMemory (&request, sizeof (request)); + + request.SetupMode = SetupEncryption; + request.WipeAlgorithm = wipeAlgorithm; + request.ZeroUnreadableSectors = zeroUnreadableSectors; + + CallDriver (TC_IOCTL_BOOT_ENCRYPTION_SETUP, &request, sizeof (request), NULL, 0); + } + + void BootEncryption::CopyFileAdmin (const wstring &sourceFile, const wstring &destinationFile) + { + if (!IsAdmin()) + { + if (!IsUacSupported()) + { + SetLastError (ERROR_ACCESS_DENIED); + throw SystemException(SRC_POS); + } + else + Elevator::CopyFile (sourceFile, destinationFile); + } + else + throw_sys_if (!::CopyFile (sourceFile.c_str(), destinationFile.c_str(), FALSE)); + } + + void BootEncryption::DeleteFileAdmin (const wstring &file) + { + if (!IsAdmin() && IsUacSupported()) + Elevator::DeleteFile (file); + else + throw_sys_if (!::DeleteFile (file.c_str())); + } + +#endif // !SETUP + + uint32 BootEncryption::ReadDriverConfigurationFlags () + { + DWORD configMap; + + if (!ReadLocalMachineRegistryDword (L"SYSTEM\\CurrentControlSet\\Services\\veracrypt", TC_DRIVER_CONFIG_REG_VALUE_NAME, &configMap)) + configMap = 0; + + return configMap; + } + + void BootEncryption::WriteBootDriveSector (uint64 offset, byte *data) + { + WriteBootDriveSectorRequest request; + request.Offset.QuadPart = offset; + memcpy (request.Data, data, sizeof (request.Data)); + + CallDriver (TC_IOCTL_WRITE_BOOT_DRIVE_SECTOR, &request, sizeof (request), NULL, 0); + } + + void BootEncryption::RegisterBootDriver (bool hiddenSystem) + { + SetDriverServiceStartType (SERVICE_BOOT_START); + + try + { + RegisterFilterDriver (false, DriveFilter); + RegisterFilterDriver (false, VolumeFilter); + RegisterFilterDriver (false, DumpFilter); + } + catch (...) { } + + try + { + RegisterFilterDriver (true, DriveFilter); + + if (hiddenSystem) + RegisterFilterDriver (true, VolumeFilter); + + RegisterFilterDriver (true, DumpFilter); + } + catch (...) + { + try { RegisterFilterDriver (false, DriveFilter); } catch (...) { } + try { RegisterFilterDriver (false, VolumeFilter); } catch (...) { } + try { RegisterFilterDriver (false, DumpFilter); } catch (...) { } + try { SetDriverServiceStartType (SERVICE_SYSTEM_START); } catch (...) { } + + throw; + } + } + + bool BootEncryption::RestartComputer (void) + { + return (::RestartComputer() != FALSE); + } +} |