/* 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 #include #include #include "Cache.h" #include "Crc.h" #include "Crypto.h" #include "Apidrvr.h" #include "EncryptedIoQueue.h" #include "Common/Endian.h" #include "Ntdriver.h" #include "Ntvol.h" #include "Volumes.h" #include "VolumeFilter.h" #include "Wipe.h" #include "DriveFilter.h" #include "Boot/Windows/BootCommon.h" static BOOL DeviceFilterActive = FALSE; BOOL BootArgsValid = FALSE; BootArguments BootArgs; static uint16 BootLoaderSegment; static BOOL BootDriveSignatureValid = FALSE; static KMUTEX MountMutex; static volatile BOOL BootDriveFound = FALSE; static DriveFilterExtension *BootDriveFilterExtension = NULL; static LARGE_INTEGER BootDriveLength; static byte BootLoaderFingerprint[WHIRLPOOL_DIGESTSIZE + SHA512_DIGESTSIZE]; static BOOL CrashDumpEnabled = FALSE; static BOOL HibernationEnabled = FALSE; static BOOL LegacyHibernationDriverFilterActive = FALSE; static byte *HibernationWriteBuffer = NULL; static MDL *HibernationWriteBufferMdl = NULL; static uint32 HibernationPreventionCount = 0; static BootEncryptionSetupRequest SetupRequest; static volatile BOOL SetupInProgress = FALSE; PKTHREAD EncryptionSetupThread = NULL; static volatile BOOL EncryptionSetupThreadAbortRequested; static KSPIN_LOCK SetupStatusSpinLock; static int64 SetupStatusEncryptedAreaEnd; static BOOL TransformWaitingForIdle; static NTSTATUS SetupResult; static WipeDecoySystemRequest WipeDecoyRequest; static volatile BOOL DecoySystemWipeInProgress = FALSE; static volatile BOOL DecoySystemWipeThreadAbortRequested; static KSPIN_LOCK DecoySystemWipeStatusSpinLock; static int64 DecoySystemWipedAreaEnd; PKTHREAD DecoySystemWipeThread = NULL; static NTSTATUS DecoySystemWipeResult; NTSTATUS LoadBootArguments () { NTSTATUS status = STATUS_UNSUCCESSFUL; PHYSICAL_ADDRESS bootArgsAddr; byte *mappedBootArgs; uint16 bootLoaderSegment; KeInitializeMutex (&MountMutex, 0); for (bootLoaderSegment = TC_BOOT_LOADER_SEGMENT; bootLoaderSegment >= TC_BOOT_LOADER_SEGMENT - 64 * 1024 / 16 && status != STATUS_SUCCESS; bootLoaderSegment -= 32 * 1024 / 16) { bootArgsAddr.QuadPart = (bootLoaderSegment << 4) + TC_BOOT_LOADER_ARGS_OFFSET; Dump ("Checking BootArguments at 0x%x\n", bootArgsAddr.LowPart); mappedBootArgs = MmMapIoSpace (bootArgsAddr, sizeof (BootArguments), MmCached); if (!mappedBootArgs) return STATUS_INSUFFICIENT_RESOURCES; if (TC_IS_BOOT_ARGUMENTS_SIGNATURE (mappedBootArgs)) { BootArguments *bootArguments = (BootArguments *) mappedBootArgs; Dump ("BootArguments found at 0x%x\n", bootArgsAddr.LowPart); DumpMem (mappedBootArgs, sizeof (BootArguments)); if (bootArguments->BootLoaderVersion == VERSION_NUM && bootArguments->BootArgumentsCrc32 != GetCrc32 ((byte *) bootArguments, (int) ((byte *) &bootArguments->BootArgumentsCrc32 - (byte *) bootArguments))) { Dump ("BootArguments CRC incorrect\n"); TC_BUG_CHECK (STATUS_CRC_ERROR); } // Sanity check: for valid boot argument, the password is less than 64 bytes long if (bootArguments->BootPassword.Length <= MAX_PASSWORD) { BootLoaderSegment = bootLoaderSegment; BootArgs = *bootArguments; BootArgsValid = TRUE; burn (bootArguments, sizeof (*bootArguments)); BootDriveSignatureValid = TRUE; Dump ("BootLoaderVersion = %x\n", (int) BootArgs.BootLoaderVersion); Dump ("HeaderSaltCrc32 = %x\n", (int) BootArgs.HeaderSaltCrc32); Dump ("CryptoInfoOffset = %x\n", (int) BootArgs.CryptoInfoOffset); Dump ("CryptoInfoLength = %d\n", (int) BootArgs.CryptoInfoLength); Dump ("HiddenSystemPartitionStart = %I64u\n", BootArgs.HiddenSystemPartitionStart); Dump ("DecoySystemPartitionStart = %I64u\n", BootArgs.DecoySystemPartitionStart); Dump ("Flags = %x\n", BootArgs.Flags); Dump ("BootDriveSignature = %x\n", BootArgs.BootDriveSignature); Dump ("BootArgumentsCrc32 = %x\n", BootArgs.BootArgumentsCrc32); if (CacheBootPassword && BootArgs.BootPassword.Length > 0) { int pim = CacheBootPim? (int) (BootArgs.Flags >> 16) : 0; AddPasswordToCache (&BootArgs.BootPassword, pim); } // clear fingerprint burn (BootLoaderFingerprint, sizeof (BootLoaderFingerprint)); status = STATUS_SUCCESS; } } MmUnmapIoSpace (mappedBootArgs, sizeof (BootArguments)); } return status; } NTSTATUS DriveFilterAddDevice (PDRIVER_OBJECT driverObject, PDEVICE_OBJECT pdo) { DriveFilterExtension *Extension; NTSTATUS status; PDEVICE_OBJECT filterDeviceObject = NULL; PDEVICE_OBJECT attachedDeviceObject; Dump ("DriveFilterAddDevice pdo=%p\n", pdo); attachedDeviceObject = IoGetAttachedDeviceReference (pdo); status = IoCreateDevice (driverObject, sizeof (DriveFilterExtension), NULL, attachedDeviceObject->DeviceType, 0, FALSE, &filterDeviceObject); ObDereferenceObject (attachedDeviceObject); if (!NT_SUCCESS (status)) { filterDeviceObject = NULL; goto err; } Extension = (DriveFilterExtension *) filterDeviceObject->DeviceExtension; memset (Extension, 0, sizeof (DriveFilterExtension)); status = IoAttachDeviceToDeviceStackSafe (filterDeviceObject, pdo, &(Extension->LowerDeviceObject)); if (!NT_SUCCESS (status)) { goto err; } if (!Extension->LowerDeviceObject) { status = STATUS_DEVICE_REMOVED; goto err; } Extension->IsDriveFilterDevice = Extension->Queue.IsFilterDevice = TRUE; Extension->DeviceObject = Extension->Queue.DeviceObject = filterDeviceObject; Extension->Pdo = pdo; Extension->Queue.LowerDeviceObject = Extension->LowerDeviceObject; IoInitializeRemoveLock (&Extension->Queue.RemoveLock, 'LRCV', 0, 0); Extension->ConfiguredEncryptedAreaStart = -1; Extension->ConfiguredEncryptedAreaEnd = -1; Extension->Queue.EncryptedAreaStart = -1; Extension->Queue.EncryptedAreaEnd = -1; Extension->Queue.EncryptedAreaEndUpdatePending = FALSE; filterDeviceObject->Flags |= Extension->LowerDeviceObject->Flags & (DO_DIRECT_IO | DO_BUFFERED_IO | DO_POWER_PAGABLE); filterDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING; DeviceFilterActive = TRUE; return status; e
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ru" lang="ru">
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>VeraCrypt - Бесплатное надёжное шифрование дисков с открытым исходным кодом</title>
<meta name="description" content="VeraCrypt это бесплатное программное обеспечение для шифрования дисков с открытым исходным кодом для Windows, Mac OS X (macOS) и Linux. В случае, если злоумышленник вынуждает вас раскрыть пароль, VeraCrypt обеспечивает правдоподобное отрицание наличия шифрования. В отличие от пофайлового шифрования, VeraCrypt шифрует данные в реальном времени (на лету), автоматически, прозрачно, требует очень мало памяти и не использует временные незашифрованные файлы."/>
<meta name="keywords" content="encryption, security, шифрование, безопасность"/>
<link href="styles.css" rel="stylesheet" type="text/css" />
</head>
<body>

<div>
<a href="Documentation.html"><img src="VeraCrypt128x128.png" alt="VeraCrypt"/></a>
</div>

<div id="menu">
	<ul>
	  <li><a href="Home.html">Начало</a></li>
	  <li><a href="/code/">Исходный код</a></li>
	  <li><a href="Downloads.html">Загрузить</a></li>
	  <li><a class="active" href="Documentation.html">Документация</a></li>
	  <li><a href="Donation.html">Поддержать разработку</a></li>
	  <li><a href="https://sourceforge.net/p/veracrypt/discussion/" target="_blank">Форум</a></li>
	</ul>
</div>

<div>
<p>
<a href="Documentation.html">Документация</a>
<img src="arrow_right.gif" alt=">>" style="margin-top: 5px">
<a href="Portable%20Mode.html">Портативный (переносной) режим</a>
</p></div>

<div class="wikidoc">
<h1>Портативный (переносной) режим</h1>
<p>Программа VeraCrypt может работать в так называемом портативном (portable) режиме. Это означает, что её
не нужно устанавливать в операционной системе, в которой она запускается. Тем не менее, при этом нужно помнить о паре вещей:</p>
<ol>
<li>Чтобы запустить VeraCrypt в портативном режиме, необходимо иметь права администратора компьютера (причины этого см. в главе
<a href="Using%20VeraCrypt%20Without%20Administrator%20Privileges.html">
<em>Использование VeraCrypt без прав администратора</em></a>).
<table border="2">
<tbody>
<tr>
<td style="text-align:left; font-size:11px; line-height:13px; font-family:Verdana,Arial,Helvetica,sans-serif; color:#ff0000; padding:15px; border:1px solid #000000">
Примечание. Независимо от того, какое ПО вы используете, если говорить о защите личных данных, в большинстве случаев
<em>небезопасно</em> работать с конфиденциальной информацией в системе, где у вас нет привилегий администратора, так как
администратор может без труда получить и скопировать ваши конфиденциальные данные, в том числе пароли и ключи.</td>
</tr>
</tbody>
</table>
</li><li>Даже если использовался портативный режим, исследовав файл реестра, можно выяснить, что в Windows запускался
VeraCrypt (и что монтировался том VeraCrypt).
</li></ol>
<p><strong>Примечание</strong>. Если для вас это проблема, см. <a href="FAQ.html#notraces" target="_blank.html">
данный вопрос</a> в FAQ.<br>
<br>
Запускать VeraCrypt в портативном режиме можно двумя способами:</p>
<ol>
<li>Извлечь файлы из самораспаковывающегося дистрибутивного пакета VeraCrypt и запустить файл
<em>VeraCrypt.exe</em>.<br>
Чтобы извлечь файлы из самораспаковывающегося дистрибутивного пакета VeraCrypt, запустите его и выберите на второй странице
мастера установки опцию <em>Извлечь</em> (вместо <em>Установить</em>).<br>
</li><li>Воспользоваться средством настройки <em>Переносного диска</em>, чтобы подготовить специальный
носимый с собой диск и запускать VeraCrypt с него.
</li></ol>
<p>Второй вариант имеет ряд преимуществ, описанных ниже в этой главе.</p>
<p>Примечание. При работе в переносном (portable) режиме драйвер VeraCrypt выгружается, когда он больше не нужен (например,
когда закрыты все копии главного приложения и/или мастера создания томов и нет смонтированных томов). Однако если
вы принудительно размонтируете том VeraCrypt, когда VeraCrypt запущен в переносном режиме, или смонтируете доступный
для записи том с файловой системой NTFS в Vista или более новой версии Windows, драйвер VeraCrypt может
<em>не</em> выгрузиться при выходе из VeraCrypt (он будет выгружен только при завершении работы системы или её
перезагрузке). Это предотвращает различные проблемы, вызванные ошибкой в ​​Windows (например, было бы невозможно снова
запустить VeraCrypt, пока есть приложения, использующие размонтированный том).</p>
<h3>Сервис &gt; Настройка Переносного диска</h3>
<p>Эта функция позволяет подготовить специальный носимый с собой диск и запускать оттуда VeraCrypt. Обратите внимание,
что такой "переносной диск" это <em>не</em> том VeraCrypt, а <em>незашифрованный</em> том. "Переносной диск" исполняемые
файлы VeraCrypt и, при необходимости, скрипт <i>autorun.inf</i> (см. ниже раздел
<em>Настройка автозапуска (файл autorun.inf)</em>). При выборе <em>Сервис &gt; Настройка Переносного диска</em>
появится окно <em>Настройка Переносного диска</em>. Далее описаны некоторые параметры в этом окне, нуждающиеся в пояснении.</p>
<h4>С мастером создания томов VeraCrypt</h4>
<p>Включите эту опцию, если вам нужно создавать новые тома VeraCrypt с помощью VeraCrypt, запускаемого с этого
Переносного диска. Отключение этой опции экономит место на Переносном диске.</p>
<h4>Настройка автозапуска (файл autorun.inf)</h4>
<p>Данная группа параметров позволяет настроить Переносной диск для автоматического запуска VeraCrypt или монтирования
указанного тома VeraCrypt при вставке диска. Это достигается путём создания на Переносном диске специального файла
сценария (скрипта) с именем &lsquo;<em>autorun.inf</em>&rsquo;. Этот файл автоматически запускается операционной
системой каждый раз, когда вставляется Переносной диск.<br>
<br>
Обратите, однако, внимание, что данная функция работает лишь с такими сменными носителями, как диски CD/DVD (для работы
с USB-флешками требуется Windows XP SP2, Vista или более новая версия Windows), и только если это разрешено в
операционной системе. В зависимости от конфигурации операционной системы эти функции автозапуска и автомонтирования
могут работать только в том случае, если файлы Переносного диска созданы на недоступном для записи CD/DVD-подобном
носителе (это не ошибка в VeraCrypt, а ограничение Windows).<br>
<br>
Также примите к сведению, что файл <em>autorun.inf</em> должен находиться в корневой папке (то есть, например, в
<em>G:\</em>, <em>X:\</em>, <em>Y:\</em> и т. д.) на <strong>незашифрованном</strong> диске, иначе эта функция
не будет работать.</p>
</div><div class="ClearBoth"></div></body></html>
berDriverWriteFunctionAFilter0 (ULONG arg0, PLARGE_INTEGER writeOffset, PMDL dataMdl, PVOID arg3) { return HiberDriverWriteFunctionFilter (0, writeOffset, dataMdl, FALSE, arg0, arg3); } static NTSTATUS HiberDriverWriteFunctionAFilter1 (ULONG arg0, PLARGE_INTEGER writeOffset, PMDL dataMdl, PVOID arg3) { return HiberDriverWriteFunctionFilter (1, writeOffset, dataMdl, FALSE, arg0, arg3); } static NTSTATUS HiberDriverWriteFunctionAFilter2 (ULONG arg0, PLARGE_INTEGER writeOffset, PMDL dataMdl, PVOID arg3) { return HiberDriverWriteFunctionFilter (2, writeOffset, dataMdl, FALSE, arg0, arg3); } static NTSTATUS HiberDriverWriteFunctionBFilter0 (PLARGE_INTEGER writeOffset, PMDL dataMdl) { return HiberDriverWriteFunctionFilter (0, writeOffset, dataMdl, TRUE, 0, NULL); } static NTSTATUS HiberDriverWriteFunctionBFilter1 (PLARGE_INTEGER writeOffset, PMDL dataMdl) { return HiberDriverWriteFunctionFilter (1, writeOffset, dataMdl, TRUE, 0, NULL); } static NTSTATUS HiberDriverWriteFunctionBFilter2 (PLARGE_INTEGER writeOffset, PMDL dataMdl) { return HiberDriverWriteFunctionFilter (2, writeOffset, dataMdl, TRUE, 0, NULL); } static NTSTATUS HiberDriverEntryFilter (int filterNumber, PVOID arg0, HiberDriverContext *hiberDriverContext) { BOOL filterInstalled = FALSE; NTSTATUS status; if (!OriginalHiberDriverEntries[filterNumber]) return STATUS_UNSUCCESSFUL; status = (*OriginalHiberDriverEntries[filterNumber]) (arg0, hiberDriverContext); if (!NT_SUCCESS (status) || !hiberDriverContext) return status; if (SetupInProgress) TC_BUG_CHECK (STATUS_INVALID_PARAMETER); if (hiberDriverContext->WriteFunctionA) { Dump ("Filtering WriteFunctionA %d\n", filterNumber); OriginalHiberDriverWriteFunctionsA[filterNumber] = hiberDriverContext->WriteFunctionA; switch (filterNumber) { case 0: hiberDriverContext->WriteFunctionA = HiberDriverWriteFunctionAFilter0; break; case 1: hiberDriverContext->WriteFunctionA = HiberDriverWriteFunctionAFilter1; break; case 2: hiberDriverContext->WriteFunctionA = HiberDriverWriteFunctionAFilter2; break; default: TC_THROW_FATAL_EXCEPTION; } filterInstalled = TRUE; } if (hiberDriverContext->WriteFunctionB) { Dump ("Filtering WriteFunctionB %d\n", filterNumber); OriginalHiberDriverWriteFunctionsB[filterNumber] = hiberDriverContext->WriteFunctionB; switch (filterNumber) { case 0: hiberDriverContext->WriteFunctionB = HiberDriverWriteFunctionBFilter0; break; case 1: hiberDriverContext->WriteFunctionB = HiberDriverWriteFunctionBFilter1; break; case 2: hiberDriverContext->WriteFunctionB = HiberDriverWriteFunctionBFilter2; break; default: TC_THROW_FATAL_EXCEPTION; } filterInstalled = TRUE; } if (filterInstalled && hiberDriverContext->PartitionStartOffset.QuadPart != 0) { HiberPartitionOffset = hiberDriverContext->PartitionStartOffset; if (BootDriveFilterExtension->Queue.RemapEncryptedArea) hiberDriverContext->PartitionStartOffset.QuadPart += BootDriveFilterExtension->Queue.RemappedAreaOffset; } return STATUS_SUCCESS; } static NTSTATUS HiberDriverEntryFilter0 (PVOID arg0, HiberDriverContext *hiberDriverContext) { return HiberDriverEntryFilter (0, arg0, hiberDriverContext); } static NTSTATUS HiberDriverEntryFilter1 (PVOID arg0, HiberDriverContext *hiberDriverContext) { return HiberDriverEntryFilter (1, arg0, hiberDriverContext); } static NTSTATUS HiberDriverEntryFilter2 (PVOID arg0, HiberDriverContext *hiberDriverContext) { return HiberDriverEntryFilter (2, arg0, hiberDriverContext); } static VOID LoadImageNotifyRoutine (PUNICODE_STRING fullImageName, HANDLE processId, PIMAGE_INFO imageInfo) { ModuleTableItem *moduleItem; LIST_ENTRY *listEntry; KIRQL origIrql; if (!imageInfo || !imageInfo->SystemModeImage || !imageInfo->ImageBase || !TCDriverObject->DriverSection) return; moduleItem = *(ModuleTableItem **) TCDriverObject->DriverSection; if (!moduleItem || !moduleItem->ModuleList.Flink) return; // Search loaded system modules for hibernation driver origIrql = KeRaiseIrqlToDpcLevel(); for (listEntry = moduleItem->ModuleList.Flink->Blink; listEntry && listEntry != TCDriverObject->DriverSection; listEntry = listEntry->Flink) { moduleItem = CONTAINING_RECORD (listEntry, ModuleTableItem, ModuleList); if (moduleItem && imageInfo->ImageBase == moduleItem->ModuleBaseAddress) { if (moduleItem->ModuleName.Buffer && moduleItem->ModuleName.Length >= 5 * sizeof (wchar_t)) { if (memcmp (moduleItem->ModuleName.Buffer, L"hiber", 5 * sizeof (wchar_t)) == 0 || memcmp (moduleItem->ModuleName.Buffer, L"Hiber", 5 * sizeof (wchar_t)) == 0 || memcmp (moduleItem->ModuleName.Buffer, L"HIBER", 5 * sizeof (wchar_t)) == 0) { HiberDriverEntry filterEntry; switch (LastHiberFilterNumber) { case 0: filterEntry = HiberDriverEntryFilter0; break; case 1: filterEntry = HiberDriverEntryFilter1; break; case 2: filterEntry = HiberDriverEntryFilter2; break; default: TC_THROW_FATAL_EXCEPTION; } if (moduleItem->ModuleEntryAddress != filterEntry) { // Install filter OriginalHiberDriverEntries[LastHiberFilterNumber] = moduleItem->ModuleEntryAddress; moduleItem->ModuleEntryAddress = filterEntry; if (++LastHiberFilterNumber > TC_MAX_HIBER_FILTER_COUNT - 1) LastHiberFilterNumber = 0; } } } break; } } KeLowerIrql (origIrql); } void StartLegacyHibernationDriverFilter () { PHYSICAL_ADDRESS highestAcceptableWriteBufferAddr; NTSTATUS status; ASSERT (KeGetCurrentIrql() == PASSIVE_LEVEL); ASSERT (!IsOSAtLeast (WIN_VISTA)); if (!TCDriverObject->DriverSection || !*(ModuleTableItem **) TCDriverObject->DriverSection) goto err; // All buffers required for hibernation must be allocated here #ifdef _WIN64 highestAcceptableWriteBufferAddr.QuadPart = 0x7FFffffFFFFULL; #else highestAcceptableWriteBufferAddr.QuadPart = 0xffffFFFFULL; #endif HibernationWriteBuffer = MmAllocateContiguousMemory (TC_HIBERNATION_WRITE_BUFFER_SIZE, highestAcceptableWriteBufferAddr); if (!HibernationWriteBuffer) goto err; HibernationWriteBufferMdl = IoAllocateMdl (HibernationWriteBuffer, TC_HIBERNATION_WRITE_BUFFER_SIZE, FALSE, FALSE, NULL); if (!HibernationWriteBufferMdl) goto err; MmBuildMdlForNonPagedPool (HibernationWriteBufferMdl); status = PsSetLoadImageNotifyRoutine (LoadImageNotifyRoutine); if (!NT_SUCCESS (status)) goto err; LegacyHibernationDriverFilterActive = TRUE; CrashDumpEnabled = FALSE; HibernationEnabled = TRUE; return; err: LegacyHibernationDriverFilterActive = FALSE; CrashDumpEnabled = FALSE; HibernationEnabled = FALSE; if (HibernationWriteBufferMdl) { IoFreeMdl (HibernationWriteBufferMdl); HibernationWriteBufferMdl = NULL; } if (HibernationWriteBuffer) { MmFreeContiguousMemory (HibernationWriteBuffer); HibernationWriteBuffer = NULL; } } static VOID SetupThreadProc (PVOID threadArg) { DriveFilterExtension *Extension = BootDriveFilterExtension; LARGE_INTEGER offset; UINT64_STRUCT dataUnit; ULONG setupBlockSize = TC_ENCRYPTION_SETUP_IO_BLOCK_SIZE; BOOL headerUpdateRequired = FALSE; int64 bytesWrittenSinceHeaderUpdate = 0; byte *buffer = NULL; byte *wipeBuffer = NULL; byte wipeRandChars[TC_WIPE_RAND_CHAR_COUNT]; byte wipeRandCharsUpdate[TC_WIPE_RAND_CHAR_COUNT]; KIRQL irql; NTSTATUS status; // generate real random values for wipeRandChars and // wipeRandCharsUpdate instead of relying on uninitialized stack memory LARGE_INTEGER iSeed; KeQuerySystemTime( &iSeed ); if (KeGetCurrentIrql() < DISPATCH_LEVEL) { ULONG ulRandom; ulRandom = RtlRandomEx( &iSeed.LowPart ); memcpy (wipeRandChars, &ulRandom, TC_WIPE_RAND_CHAR_COUNT); ulRandom = RtlRandomEx( &ulRandom ); memcpy (wipeRandCharsUpdate, &ulRandom, TC_WIPE_RAND_CHAR_COUNT); burn (&ulRandom, sizeof(ulRandom)); } else { byte digest[SHA512_DIGESTSIZE]; sha512_ctx tctx; sha512_begin (&tctx); sha512_hash ((unsigned char *) &(iSeed.QuadPart), sizeof(iSeed.QuadPart), &tctx); sha512_end (digest, &tctx); memcpy (wipeRandChars, digest, TC_WIPE_RAND_CHAR_COUNT); memcpy (wipeRandCharsUpdate, &digest[SHA512_DIGESTSIZE - TC_WIPE_RAND_CHAR_COUNT], TC_WIPE_RAND_CHAR_COUNT); burn (digest, SHA512_DIGESTSIZE); burn (&tctx, sizeof (tctx)); } burn (&iSeed, sizeof(iSeed)); SetupResult = STATUS_UNSUCCESSFUL; // Make sure volume header can be updated if (Extension->HeaderCryptoInfo == NULL) { SetupResult = STATUS_INVALID_PARAMETER; goto ret; } buffer = TCalloc (TC_ENCRYPTION_SETUP_IO_BLOCK_SIZE); if (!buffer) { SetupResult = STATUS_INSUFFICIENT_RESOURCES; goto ret; } if (SetupRequest.SetupMode == SetupEncryption && SetupRequest.WipeAlgorithm != TC_WIPE_NONE) { wipeBuffer = TCalloc (TC_ENCRYPTION_SETUP_IO_BLOCK_SIZE); if (!wipeBuffer) { SetupResult = STATUS_INSUFFICIENT_RESOURCES; goto ret; } } while (!NT_SUCCESS (EncryptedIoQueueHoldWhenIdle (&Extension->Queue, 1000))) { if (EncryptionSetupThreadAbortRequested) goto abort; TransformWaitingForIdle = TRUE; } TransformWaitingForIdle = FALSE; switch (SetupRequest.SetupMode) { case SetupEncryption: Dump ("Encrypting...\n"); if (Extension->Queue.EncryptedAreaStart == -1 || Extension->Queue.EncryptedAreaEnd == -1) { // Start encryption Extension->Queue.EncryptedAreaStart = Extension->ConfiguredEncryptedAreaStart; Extension->Queue.EncryptedAreaEnd = -1; offset.QuadPart = Extension->ConfiguredEncryptedAreaStart; } else { // Resume aborted encryption if (Extension->Queue.EncryptedAreaEnd == Extension->ConfiguredEncryptedAreaEnd) goto err; offset.QuadPart = Extension->Queue.EncryptedAreaEnd + 1; } break; case SetupDecryption: Dump ("Decrypting...\n"); if (Extension->Queue.EncryptedAreaStart == -1 || Extension->Queue.EncryptedAreaEnd == -1) { SetupResult = STATUS_SUCCESS; goto abort; } offset.QuadPart = Extension->Queue.EncryptedAreaEnd + 1; break; default: goto err; } EncryptedIoQueueResumeFromHold (&Extension->Queue); Dump ("EncryptedAreaStart=%I64d\n", Extension->Queue.EncryptedAreaStart); Dump ("EncryptedAreaEnd=%I64d\n", Extension->Queue.EncryptedAreaEnd); Dump ("ConfiguredEncryptedAreaStart=%I64d\n", Extension->ConfiguredEncryptedAreaStart); Dump ("ConfiguredEncryptedAreaEnd=%I64d\n", Extension->ConfiguredEncryptedAreaEnd); Dump ("offset=%I64d\n", offset.QuadPart); Dump ("EncryptedAreaStart=%I64d (%I64d) EncryptedAreaEnd=%I64d\n", Extension->Queue.EncryptedAreaStart / 1024 / 1024, Extension->Queue.EncryptedAreaStart, Extension->Queue.EncryptedAreaEnd / 1024 / 1024); while (!EncryptionSetupThreadAbortRequested) { if (SetupRequest.SetupMode == SetupEncryption) { if (offset.QuadPart + setupBlockSize > Extension->ConfiguredEncryptedAreaEnd + 1) setupBlockSize = (ULONG) (Extension->ConfiguredEncryptedAreaEnd + 1 - offset.QuadPart); if (offset.QuadPart > Extension->ConfiguredEncryptedAreaEnd) break; } else { if (offset.QuadPart - setupBlockSize < Extension->Queue.EncryptedAreaStart) setupBlockSize = (ULONG) (offset.QuadPart - Extension->Queue.EncryptedAreaStart); offset.QuadPart -= setupBlockSize; if (setupBlockSize == 0 || offset.QuadPart < Extension->Queue.EncryptedAreaStart) break; } while (!NT_SUCCESS (EncryptedIoQueueHoldWhenIdle (&Extension->Queue, 500))) { if (EncryptionSetupThreadAbortRequested) goto abort; TransformWaitingForIdle = TRUE; } TransformWaitingForIdle = FALSE; status = TCReadDevice (BootDriveFilterExtension->LowerDeviceObject, buffer, offset, setupBlockSize); if (!NT_SUCCESS (status)) { Dump ("TCReadDevice error %x offset=%I64d\n", status, offset.QuadPart); if (SetupRequest.ZeroUnreadableSectors && SetupRequest.SetupMode == SetupEncryption) { // Zero unreadable sectors uint64 zeroedSectorCount; status = ZeroUnreadableSectors (BootDriveFilterExtension->LowerDeviceObject, offset, setupBlockSize, &zeroedSectorCount); if (!NT_SUCCESS (status)) { SetupResult = status; goto err; } // Retry read status = TCReadDevice (BootDriveFilterExtension->LowerDeviceObject, buffer, offset, setupBlockSize); if (!NT_SUCCESS (status)) { SetupResult = status; goto err; } } else if (SetupRequest.DiscardUnreadableEncryptedSectors && SetupRequest.SetupMode == SetupDecryption) { // Discard unreadable encrypted sectors uint64 badSectorCount; status = ReadDeviceSkipUnreadableSectors (BootDriveFilterExtension->LowerDeviceObject, buffer, offset, setupBlockSize, &badSectorCount); if (!NT_SUCCESS (status)) { SetupResult = status; goto err; } } else { SetupResult = status; goto err; } } dataUnit.Value = offset.QuadPart / ENCRYPTION_DATA_UNIT_SIZE; if (SetupRequest.SetupMode == SetupEncryption) { EncryptDataUnits (buffer, &dataUnit, setupBlockSize / ENCRYPTION_DATA_UNIT_SIZE, Extension->Queue.CryptoInfo); if (SetupRequest.WipeAlgorithm != TC_WIPE_NONE) { byte wipePass; int wipePassCount = GetWipePassCount (SetupRequest.WipeAlgorithm); if (wipePassCount <= 0) { SetupResult = STATUS_INVALID_PARAMETER; goto err; } for (wipePass = 1; wipePass <= wipePassCount; ++wipePass) { if (!WipeBuffer (SetupRequest.WipeAlgorithm, wipeRandChars, wipePass, wipeBuffer, setupBlockSize)) { ULONG i; for (i = 0; i < setupBlockSize; ++i) { wipeBuffer[i] = buffer[i] + wipePass; } EncryptDataUnits (wipeBuffer, &dataUnit, setupBlockSize / ENCRYPTION_DATA_UNIT_SIZE, Extension->Queue.CryptoInfo); memcpy (wipeRandCharsUpdate, wipeBuffer, sizeof (wipeRandCharsUpdate)); } status = TCWriteDevice (BootDriveFilterExtension->LowerDeviceObject, wipeBuffer, offset, setupBlockSize); if (!NT_SUCCESS (status)) { // Undo failed write operation DecryptDataUnits (buffer, &dataUnit, setupBlockSize / ENCRYPTION_DATA_UNIT_SIZE, Extension->Queue.CryptoInfo); TCWriteDevice (BootDriveFilterExtension->LowerDeviceObject, buffer, offset, setupBlockSize); SetupResult = status; goto err; } } memcpy (wipeRandChars, wipeRandCharsUpdate, sizeof (wipeRandCharsUpdate)); } } else { DecryptDataUnits (buffer, &dataUnit, setupBlockSize / ENCRYPTION_DATA_UNIT_SIZE, Extension->Queue.CryptoInfo); } status = TCWriteDevice (BootDriveFilterExtension->LowerDeviceObject, buffer, offset, setupBlockSize); if (!NT_SUCCESS (status)) { Dump ("TCWriteDevice error %x\n", status); // Undo failed write operation if (SetupRequest.SetupMode == SetupEncryption) DecryptDataUnits (buffer, &dataUnit, setupBlockSize / ENCRYPTION_DATA_UNIT_SIZE, Extension->Queue.CryptoInfo); else EncryptDataUnits (buffer, &dataUnit, setupBlockSize / ENCRYPTION_DATA_UNIT_SIZE, Extension->Queue.CryptoInfo); TCWriteDevice (BootDriveFilterExtension->LowerDeviceObject, buffer, offset, setupBlockSize); SetupResult = status; goto err; } if (SetupRequest.SetupMode == SetupEncryption) offset.QuadPart += setupBlockSize; Extension->Queue.EncryptedAreaEndUpdatePending = TRUE; Extension->Queue.EncryptedAreaEnd = offset.QuadPart - 1; Extension->Queue.EncryptedAreaEndUpdatePending = FALSE; headerUpdateRequired = TRUE; EncryptedIoQueueResumeFromHold (&Extension->Queue); KeAcquireSpinLock (&SetupStatusSpinLock, &irql); SetupStatusEncryptedAreaEnd = Extension->Queue.EncryptedAreaEnd; KeReleaseSpinLock (&SetupStatusSpinLock, irql); // Update volume header bytesWrittenSinceHeaderUpdate += setupBlockSize; if (bytesWrittenSinceHeaderUpdate >= TC_ENCRYPTION_SETUP_HEADER_UPDATE_THRESHOLD) { status = SaveDriveVolumeHeader (Extension); ASSERT (NT_SUCCESS (status)); if (NT_SUCCESS (status)) { headerUpdateRequired = FALSE; bytesWrittenSinceHeaderUpdate = 0; } } } abort: SetupResult = STATUS_SUCCESS; err: if (Extension->Queue.EncryptedAreaEnd == -1) Extension->Queue.EncryptedAreaStart = -1; if (EncryptedIoQueueIsSuspended (&Extension->Queue)) EncryptedIoQueueResumeFromHold (&Extension->Queue); if (SetupRequest.SetupMode == SetupDecryption && Extension->Queue.EncryptedAreaStart >= Extension->Queue.EncryptedAreaEnd) { while (!NT_SUCCESS (EncryptedIoQueueHoldWhenIdle (&Extension->Queue, 0))); Extension->ConfiguredEncryptedAreaStart = Extension->ConfiguredEncryptedAreaEnd = -1; Extension->Queue.EncryptedAreaStart = Extension->Queue.EncryptedAreaEnd = -1; EncryptedIoQueueResumeFromHold (&Extension->Queue); headerUpdateRequired = TRUE; } Dump ("Setup completed: EncryptedAreaStart=%I64d (%I64d) EncryptedAreaEnd=%I64d (%I64d)\n", Extension->Queue.EncryptedAreaStart / 1024 / 1024, Extension->Queue.EncryptedAreaStart, Extension->Queue.EncryptedAreaEnd / 1024 / 1024, Extension->Queue.EncryptedAreaEnd); if (headerUpdateRequired) { status = SaveDriveVolumeHeader (Extension); if (!NT_SUCCESS (status) && NT_SUCCESS (SetupResult)) SetupResult = status; } if (SetupRequest.SetupMode == SetupDecryption && Extension->ConfiguredEncryptedAreaEnd == -1 && Extension->DriveMounted) { while (!RootDeviceControlMutexAcquireNoWait() && !EncryptionSetupThreadAbortRequested) { TCSleep (10); } // Disable hibernation (resume would fail due to a change in the system memory map) HibernationEnabled = FALSE; DismountDrive (Extension, FALSE); if (!EncryptionSetupThreadAbortRequested) RootDeviceControlMutexRelease(); } ret: if (buffer) { burn (buffer, TC_ENCRYPTION_SETUP_IO_BLOCK_SIZE); TCfree (buffer); } if (wipeBuffer) { burn (wipeBuffer, TC_ENCRYPTION_SETUP_IO_BLOCK_SIZE); TCfree (wipeBuffer); } burn (wipeRandChars, TC_WIPE_RAND_CHAR_COUNT); burn (wipeRandCharsUpdate, TC_WIPE_RAND_CHAR_COUNT); SetupInProgress = FALSE; PsTerminateSystemThread (SetupResult); } NTSTATUS StartBootEncryptionSetup (PDEVICE_OBJECT DeviceObject, PIRP irp, PIO_STACK_LOCATION irpSp) { NTSTATUS status; if (!UserCanAccessDriveDevice()) return STATUS_ACCESS_DENIED; if (SetupInProgress || !BootDriveFound || !BootDriveFilterExtension || !BootDriveFilterExtension->DriveMounted || BootDriveFilterExtension->HiddenSystem || irpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof (BootEncryptionSetupRequest)) return STATUS_INVALID_PARAMETER; if (EncryptionSetupThread) AbortBootEncryptionSetup(); SetupRequest = *(BootEncryptionSetupRequest *) irp->AssociatedIrp.SystemBuffer; EncryptionSetupThreadAbortRequested = FALSE; KeInitializeSpinLock (&SetupStatusSpinLock); SetupStatusEncryptedAreaEnd = BootDriveFilterExtension ? BootDriveFilterExtension->Queue.EncryptedAreaEnd : -1; SetupInProgress = TRUE; status = TCStartThread (SetupThreadProc, DeviceObject, &EncryptionSetupThread); if (!NT_SUCCESS (status)) SetupInProgress = FALSE; return status; } void GetBootDriveVolumeProperties (PIRP irp, PIO_STACK_LOCATION irpSp) { if (ValidateIOBufferSize (irp, sizeof (VOLUME_PROPERTIES_STRUCT), ValidateOutput)) { DriveFilterExtension *Extension = BootDriveFilterExtension; VOLUME_PROPERTIES_STRUCT *prop = (VOLUME_PROPERTIES_STRUCT *) irp->AssociatedIrp.SystemBuffer; memset (prop, 0, sizeof (*prop)); if (!BootDriveFound || !Extension || !Extension->DriveMounted) { irp->IoStatus.Status = STATUS_INVALID_PARAMETER; irp->IoStatus.Information = 0; } else { prop->hiddenVolume = Extension->Queue.CryptoInfo->hiddenVolume; prop->diskLength = Extension->ConfiguredEncryptedAreaEnd + 1 - Extension->ConfiguredEncryptedAreaStart; prop->ea = Extension->Queue.CryptoInfo->ea; prop->mode = Extension->Queue.CryptoInfo->mode; prop->pkcs5 = Extension->Queue.CryptoInfo->pkcs5; prop->pkcs5Iterations = Extension->Queue.CryptoInfo->noIterations; prop->volumePim = Extension->Queue.CryptoInfo->volumePim; #if 0 prop->volumeCreationTime = Extension->Queue.CryptoInfo->volume_creation_time; prop->headerCreationTime = Extension->Queue.CryptoInfo->header_creation_time; #endif prop->volFormatVersion = Extension->Queue.CryptoInfo->LegacyVolume ? TC_VOLUME_FORMAT_VERSION_PRE_6_0 : TC_VOLUME_FORMAT_VERSION; prop->totalBytesRead = Extension->Queue.TotalBytesRead; prop->totalBytesWritten = Extension->Queue.TotalBytesWritten; irp->IoStatus.Information = sizeof (VOLUME_PROPERTIES_STRUCT); irp->IoStatus.Status = STATUS_SUCCESS; } } } void GetBootEncryptionStatus (PIRP irp, PIO_STACK_LOCATION irpSp) { /* IMPORTANT: Do NOT add any potentially time-consuming operations to this function. */ if (ValidateIOBufferSize (irp, sizeof (BootEncryptionStatus), ValidateOutput)) { DriveFilterExtension *Extension = BootDriveFilterExtension; BootEncryptionStatus *bootEncStatus = (BootEncryptionStatus *) irp->AssociatedIrp.SystemBuffer; memset (bootEncStatus, 0, sizeof (*bootEncStatus)); if (BootArgsValid) bootEncStatus->BootLoaderVersion = BootArgs.BootLoaderVersion; bootEncStatus->DeviceFilterActive = DeviceFilterActive; bootEncStatus->SetupInProgress = SetupInProgress; bootEncStatus->SetupMode = SetupRequest.SetupMode; bootEncStatus->TransformWaitingForIdle = TransformWaitingForIdle; if (!BootDriveFound || !Extension || !Extension->DriveMounted) { bootEncStatus->DriveEncrypted = FALSE; bootEncStatus->DriveMounted = FALSE; bootEncStatus->VolumeHeaderPresent = FALSE; } else { bootEncStatus->DriveMounted = Extension->DriveMounted; bootEncStatus->VolumeHeaderPresent = Extension->VolumeHeaderPresent; bootEncStatus->DriveEncrypted = Extension->Queue.EncryptedAreaStart != -1; bootEncStatus->BootDriveLength = BootDriveLength; bootEncStatus->ConfiguredEncryptedAreaStart = Extension->ConfiguredEncryptedAreaStart; bootEncStatus->ConfiguredEncryptedAreaEnd = Extension->ConfiguredEncryptedAreaEnd; bootEncStatus->EncryptedAreaStart = Extension->Queue.EncryptedAreaStart; if (SetupInProgress) { KIRQL irql; KeAcquireSpinLock (&SetupStatusSpinLock, &irql); bootEncStatus->EncryptedAreaEnd = SetupStatusEncryptedAreaEnd; KeReleaseSpinLock (&SetupStatusSpinLock, irql); } else bootEncStatus->EncryptedAreaEnd = Extension->Queue.EncryptedAreaEnd; bootEncStatus->VolumeHeaderSaltCrc32 = Extension->VolumeHeaderSaltCrc32; bootEncStatus->HibernationPreventionCount = HibernationPreventionCount; bootEncStatus->HiddenSysLeakProtectionCount = HiddenSysLeakProtectionCount; bootEncStatus->HiddenSystem = Extension->HiddenSystem; if (Extension->HiddenSystem) bootEncStatus->HiddenSystemPartitionStart = BootArgs.HiddenSystemPartitionStart; } irp->IoStatus.Information = sizeof (BootEncryptionStatus); irp->IoStatus.Status = STATUS_SUCCESS; } } void GetBootLoaderVersion (PIRP irp, PIO_STACK_LOCATION irpSp) { if (ValidateIOBufferSize (irp, sizeof (uint16), ValidateOutput)) { if (BootArgsValid) { *(uint16 *) irp->AssociatedIrp.SystemBuffer = BootArgs.BootLoaderVersion; irp->IoStatus.Information = sizeof (uint16); irp->IoStatus.Status = STATUS_SUCCESS; } else { irp->IoStatus.Status = STATUS_INVALID_PARAMETER; irp->IoStatus.Information = 0; } } } void GetBootLoaderFingerprint (PIRP irp, PIO_STACK_LOCATION irpSp) { if (ValidateIOBufferSize (irp, sizeof (BootLoaderFingerprintRequest), ValidateOutput)) { irp->IoStatus.Information = 0; if (BootArgsValid && BootDriveFound && BootDriveFilterExtension && BootDriveFilterExtension->DriveMounted && BootDriveFilterExtension->HeaderCryptoInfo) { BootLoaderFingerprintRequest *bootLoaderFingerprint = (BootLoaderFingerprintRequest *) irp->AssociatedIrp.SystemBuffer; /* compute the fingerprint again and check if it is the same as the one retrieved during boot */ char *header = TCalloc (TC_BOOT_ENCRYPTION_VOLUME_HEADER_SIZE); if (!header) { irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; } else { memcpy (bootLoaderFingerprint->Fingerprint, BootLoaderFingerprint, sizeof (BootLoaderFingerprint)); ComputeBootLoaderFingerprint (BootDriveFilterExtension->LowerDeviceObject, header); burn (header, TC_BOOT_ENCRYPTION_VOLUME_HEADER_SIZE); TCfree (header); if (0 == memcmp (bootLoaderFingerprint->Fingerprint, BootLoaderFingerprint, sizeof (BootLoaderFingerprint))) { irp->IoStatus.Information = sizeof (BootLoaderFingerprintRequest); irp->IoStatus.Status = STATUS_SUCCESS; } else { /* fingerprint mismatch.*/ irp->IoStatus.Status = STATUS_INVALID_IMAGE_HASH; } } } else { irp->IoStatus.Status = STATUS_INVALID_PARAMETER; } } } void GetBootEncryptionAlgorithmName (PIRP irp, PIO_STACK_LOCATION irpSp) { if (ValidateIOBufferSize (irp, sizeof (GetBootEncryptionAlgorithmNameRequest), ValidateOutput)) { if (BootDriveFilterExtension && BootDriveFilterExtension->DriveMounted) { wchar_t BootEncryptionAlgorithmNameW[256]; wchar_t BootPrfAlgorithmNameW[256]; GetBootEncryptionAlgorithmNameRequest *request = (GetBootEncryptionAlgorithmNameRequest *) irp->AssociatedIrp.SystemBuffer; EAGetName (BootEncryptionAlgorithmNameW, BootDriveFilterExtension->Queue.CryptoInfo->ea, 0); HashGetName2 (BootPrfAlgorithmNameW, BootDriveFilterExtension->Queue.CryptoInfo->pkcs5); RtlStringCbPrintfA (request->BootEncryptionAlgorithmName, sizeof (request->BootEncryptionAlgorithmName), "%S", BootEncryptionAlgorithmNameW); RtlStringCbPrintfA (request->BootPrfAlgorithmName, sizeof (request->BootPrfAlgorithmName), "%S", BootPrfAlgorithmNameW); irp->IoStatus.Information = sizeof (GetBootEncryptionAlgorithmNameRequest); irp->IoStatus.Status = STATUS_SUCCESS; } else { irp->IoStatus.Status = STATUS_INVALID_PARAMETER; irp->IoStatus.Information = 0; } } } NTSTATUS GetSetupResult() { return SetupResult; } BOOL IsBootDriveMounted () { return BootDriveFilterExtension && BootDriveFilterExtension->DriveMounted; } BOOL IsBootEncryptionSetupInProgress () { return SetupInProgress; } BOOL IsHiddenSystemRunning () { return BootDriveFilterExtension && BootDriveFilterExtension->HiddenSystem; } DriveFilterExtension *GetBootDriveFilterExtension () { return BootDriveFilterExtension; } CRYPTO_INFO *GetSystemDriveCryptoInfo () { return BootDriveFilterExtension->Queue.CryptoInfo; } NTSTATUS AbortBootEncryptionSetup () { if (!IoIsSystemThread (PsGetCurrentThread()) && !UserCanAccessDriveDevice()) return STATUS_ACCESS_DENIED; if (EncryptionSetupThread) { EncryptionSetupThreadAbortRequested = TRUE; TCStopThread (EncryptionSetupThread, NULL); EncryptionSetupThread = NULL; } return STATUS_SUCCESS; } static VOID DecoySystemWipeThreadProc (PVOID threadArg) { DriveFilterExtension *Extension = BootDriveFilterExtension; LARGE_INTEGER offset; UINT64_STRUCT dataUnit; ULONG wipeBlockSize = TC_ENCRYPTION_SETUP_IO_BLOCK_SIZE; CRYPTO_INFO *wipeCryptoInfo = NULL; byte *wipeBuffer = NULL; byte *wipeRandBuffer = NULL; byte wipeRandChars[TC_WIPE_RAND_CHAR_COUNT]; int wipePass, wipePassCount; int ea = Extension->Queue.CryptoInfo->ea; KIRQL irql; NTSTATUS status; DecoySystemWipeResult = STATUS_UNSUCCESSFUL; wipeBuffer = TCalloc (TC_ENCRYPTION_SETUP_IO_BLOCK_SIZE); if (!wipeBuffer) { DecoySystemWipeResult = STATUS_INSUFFICIENT_RESOURCES; goto ret; } wipeRandBuffer = TCalloc (TC_ENCRYPTION_SETUP_IO_BLOCK_SIZE); if (!wipeRandBuffer) { DecoySystemWipeResult = STATUS_INSUFFICIENT_RESOURCES; goto ret; } wipeCryptoInfo = crypto_open(); if (!wipeCryptoInfo) { DecoySystemWipeResult = STATUS_INSUFFICIENT_RESOURCES; goto ret; } wipeCryptoInfo->ea = ea; wipeCryptoInfo->mode = Extension->Queue.CryptoInfo->mode; if (EAInit (ea, WipeDecoyRequest.WipeKey, wipeCryptoInfo->ks) != ERR_SUCCESS) { DecoySystemWipeResult = STATUS_INVALID_PARAMETER; goto ret; } memcpy (wipeCryptoInfo->k2, WipeDecoyRequest.WipeKey + EAGetKeySize (ea), EAGetKeySize (ea)); if (!EAInitMode (wipeCryptoInfo)) { DecoySystemWipeResult = STATUS_INVALID_PARAMETER; goto err; } EncryptDataUnits (wipeRandBuffer, &dataUnit, wipeBlockSize / ENCRYPTION_DATA_UNIT_SIZE, wipeCryptoInfo); memcpy (wipeRandChars, wipeRandBuffer, sizeof (wipeRandChars)); burn (WipeDecoyRequest.WipeKey, sizeof (WipeDecoyRequest.WipeKey)); offset.QuadPart = Extension->ConfiguredEncryptedAreaStart; Dump ("Wiping decoy system: start offset = %I64d\n", offset.QuadPart); while (!DecoySystemWipeThreadAbortRequested) { if (offset.QuadPart + wipeBlockSize > Extension->ConfiguredEncryptedAreaEnd + 1) wipeBlockSize = (ULONG) (Extension->ConfiguredEncryptedAreaEnd + 1 - offset.QuadPart); if (offset.QuadPart > Extension->ConfiguredEncryptedAreaEnd) break; wipePassCount = GetWipePassCount (WipeDecoyRequest.WipeAlgorithm); if (wipePassCount <= 0) { DecoySystemWipeResult = STATUS_INVALID_PARAMETER; goto err; } for (wipePass = 1; wipePass <= wipePassCount; ++wipePass) { if (!WipeBuffer (WipeDecoyRequest.WipeAlgorithm, wipeRandChars, wipePass, wipeBuffer, wipeBlockSize)) { dataUnit.Value = offset.QuadPart / ENCRYPTION_DATA_UNIT_SIZE; EncryptDataUnits (wipeRandBuffer, &dataUnit, wipeBlockSize / ENCRYPTION_DATA_UNIT_SIZE, wipeCryptoInfo); memcpy (wipeBuffer, wipeRandBuffer, wipeBlockSize); } while (!NT_SUCCESS (EncryptedIoQueueHoldWhenIdle (&Extension->Queue, 500))) { if (DecoySystemWipeThreadAbortRequested) goto abort; } status = TCWriteDevice (BootDriveFilterExtension->LowerDeviceObject, wipeBuffer, offset, wipeBlockSize); if (!NT_SUCCESS (status)) { DecoySystemWipeResult = status; goto err; } EncryptedIoQueueResumeFromHold (&Extension->Queue); } offset.QuadPart += wipeBlockSize; KeAcquireSpinLock (&DecoySystemWipeStatusSpinLock, &irql); DecoySystemWipedAreaEnd = offset.QuadPart - 1; KeReleaseSpinLock (&DecoySystemWipeStatusSpinLock, irql); } abort: DecoySystemWipeResult = STATUS_SUCCESS; err: if (EncryptedIoQueueIsSuspended (&Extension->Queue)) EncryptedIoQueueResumeFromHold (&Extension->Queue); Dump ("Wipe end: DecoySystemWipedAreaEnd=%I64d (%I64d)\n", DecoySystemWipedAreaEnd, DecoySystemWipedAreaEnd / 1024 / 1024); ret: if (wipeCryptoInfo) crypto_close (wipeCryptoInfo); if (wipeRandBuffer) TCfree (wipeRandBuffer); if (wipeBuffer) TCfree (wipeBuffer); DecoySystemWipeInProgress = FALSE; PsTerminateSystemThread (DecoySystemWipeResult); } NTSTATUS StartDecoySystemWipe (PDEVICE_OBJECT DeviceObject, PIRP irp, PIO_STACK_LOCATION irpSp) { NTSTATUS status; WipeDecoySystemRequest *request; if (!UserCanAccessDriveDevice()) return STATUS_ACCESS_DENIED; if (!IsHiddenSystemRunning() || irpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof (WipeDecoySystemRequest)) return STATUS_INVALID_PARAMETER; if (DecoySystemWipeInProgress) return STATUS_SUCCESS; if (DecoySystemWipeThread) AbortDecoySystemWipe(); request = (WipeDecoySystemRequest *) irp->AssociatedIrp.SystemBuffer; WipeDecoyRequest = *request; burn (request->WipeKey, sizeof (request->WipeKey)); DecoySystemWipeThreadAbortRequested = FALSE; KeInitializeSpinLock (&DecoySystemWipeStatusSpinLock); DecoySystemWipedAreaEnd = BootDriveFilterExtension->ConfiguredEncryptedAreaStart; DecoySystemWipeInProgress = TRUE; status = TCStartThread (DecoySystemWipeThreadProc, DeviceObject, &DecoySystemWipeThread); if (!NT_SUCCESS (status)) DecoySystemWipeInProgress = FALSE; return status; } BOOL IsDecoySystemWipeInProgress() { return DecoySystemWipeInProgress; } void GetDecoySystemWipeStatus (PIRP irp, PIO_STACK_LOCATION irpSp) { if (ValidateIOBufferSize (irp, sizeof (DecoySystemWipeStatus), ValidateOutput)) { DecoySystemWipeStatus *wipeStatus = (DecoySystemWipeStatus *) irp->AssociatedIrp.SystemBuffer; if (!IsHiddenSystemRunning()) { irp->IoStatus.Status = STATUS_INVALID_PARAMETER; irp->IoStatus.Information = 0; } else { wipeStatus->WipeInProgress = DecoySystemWipeInProgress; wipeStatus->WipeAlgorithm = WipeDecoyRequest.WipeAlgorithm; if (DecoySystemWipeInProgress) { KIRQL irql; KeAcquireSpinLock (&DecoySystemWipeStatusSpinLock, &irql); wipeStatus->WipedAreaEnd = DecoySystemWipedAreaEnd; KeReleaseSpinLock (&DecoySystemWipeStatusSpinLock, irql); } else wipeStatus->WipedAreaEnd = DecoySystemWipedAreaEnd; irp->IoStatus.Information = sizeof (DecoySystemWipeStatus); irp->IoStatus.Status = STATUS_SUCCESS; } } } NTSTATUS GetDecoySystemWipeResult() { return DecoySystemWipeResult; } NTSTATUS AbortDecoySystemWipe () { if (!IoIsSystemThread (PsGetCurrentThread()) && !UserCanAccessDriveDevice()) return STATUS_ACCESS_DENIED; if (DecoySystemWipeThread) { DecoySystemWipeThreadAbortRequested = TRUE; TCStopThread (DecoySystemWipeThread, NULL); DecoySystemWipeThread = NULL; } return STATUS_SUCCESS; } uint64 GetBootDriveLength () { return BootDriveLength.QuadPart; } NTSTATUS WriteBootDriveSector (PIRP irp, PIO_STACK_LOCATION irpSp) { WriteBootDriveSectorRequest *request; if (!UserCanAccessDriveDevice()) return STATUS_ACCESS_DENIED; if (!BootDriveFilterExtension || irpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof (WriteBootDriveSectorRequest)) return STATUS_INVALID_PARAMETER; request = (WriteBootDriveSectorRequest *) irp->AssociatedIrp.SystemBuffer; return TCWriteDevice (BootDriveFilterExtension->LowerDeviceObject, request->Data, request->Offset, sizeof (request->Data)); }