TrueCrypt 6.2a原理及代码分析(2) – Raphael's Dairy

1 业务架构分析

   TrueCrypt模块通过Windows操作系统加载,模块驱动在入口接口中作了初始化:初始化了密码算法、加载了启动参数并创建了业务框架。

   模块驱动初始化完成后,整个TrueCrypt模块分为了两部分:与Windows操作系统交互部分和业务流程部分。与Windows操作系统交互部分通过创建设备对象来与Windows 操作系统的I/O管理器进行数据交互;业务流程部分通过业务架构进行工作;他们之间的交互通过队列来传递数据流。

   这样基本形成了从上到下和从下到上两种数据流,共cpu个数 * 2 条数据流,每条数据流通过队列和线程池实现了半异步和半同步的设计模式。

1.1 主要数据结构

三种工作队列状态
typedef enum
{
WorkItemFree,
WorkItemReady,
WorkItemBusy
} WorkItemState;

三种工作队列类型

typedef enum
{
EncryptDataUnitsWork,
DecryptDataUnitsWork,
DeriveKeyWork
} EncryptionThreadPoolWorkType;

/* 加密相关的参数 :加密算法类型,密钥,加密磁盘元数据等 */
typedef struct CRYPTO_INFO_t
{
int ea;      /* Encryption algorithm ID */
int mode;     /* Mode of operation (e.g., XTS) */
unsigned __int8 ks[MAX_EXPANDED_KEY]; /* Primary key schedule (if it is a cascade, it conatins multiple concatenated keys) */
unsigned __int8 ks2[MAX_EXPANDED_KEY]; /* Secondary key schedule (if cascade, multiple concatenated) for XTS mode. */

BOOL hiddenVolume;    // Indicates whether the volume is mounted/mountable as hidden volume

#ifndef TC_WINDOWS_BOOT

#endif // TC_WINDOWS_BOOT

UINT64_STRUCT VolumeSize;

UINT64_STRUCT EncryptedAreaStart;
UINT64_STRUCT EncryptedAreaLength;

uint32 HeaderFlags;

} CRYPTO_INFO, *PCRYPTO_INFO;

/* 加密队列结构 */
typedef struct EncryptionThreadPoolWorkItemStruct
{
WorkItemState State; /* 状态 */
EncryptionThreadPoolWorkType Type; /* 类型 */

TC_EVENT ItemCompletedEvent; /* 异步完成事件 */

struct EncryptionThreadPoolWorkItemStruct *FirstFragment;
LONG OutstandingFragmentCount;

/* 工作参数 */
union
{
   /* EncryptDataUnitsWork/DecryptDataUnitsWork 类型队列工作参数 */
   struct
   {
    PCRYPTO_INFO CryptoInfo;
    byte *Data;
    UINT64_STRUCT StartUnitNo;
    TC_LARGEST_COMPILER_UINT UnitCount;

   } Encryption;

   /* DeriveKeyWork 类型队列工作参数 */
   struct
   {
    TC_EVENT *CompletionEvent;
    LONG *CompletionFlag;
    char *DerivedKey;
    int IterationCount;
    TC_EVENT *NoOutstandingWorkItemEvent;
    LONG *OutstandingWorkItemCount;
    char *Password;
    int PasswordLength;
    int Pkcs5Prf;
    char *Salt;

   } KeyDerivation;
};

} EncryptionThreadPoolWorkItem;

2 数据处理流程

   TrueCrypt模块启动后,创建了业务框架,其中最重要的数据处理流程(数据的加密/解密/密钥生成)。TrueCrypt模块这部分设计很巧妙,使用了半同步/半异步的设计模式,并结合了多核条件下数据同步技术。

   TrueCrypt根据CPU个数,创建了相应的线程(我们这里给叫做数据处理线程)。这些线程开始时分别选择一个工作队列,等待数据的到来。一旦有数据进入队列,根据数据的类型,进行相应的处理;处理完毕后,通知队列的状态维护线程数据处理完毕,请维护队列状态;然后自己根据游标选择下一个要处理的队列进行处理;为什么不直接选择刚处理完的队列呢?因为此时刚处理完的队列状态还没有恢复到准备阶段,为了提高处理速度,选择下一个准备好的队列,进行处理。具体请看草图:

主要的代码分析如下:

static TC_THREAD_PROC EncryptionThreadProc (void *threadArg)
{
EncryptionThreadPoolWorkItem *workItem;

while (!StopPending)
{
   /* 队列是多核的共享资源,需要保护 */
   TC_ACQUIRE_MUTEX (&DequeueMutex);

   workItem = &WorkItemQueue[DequeuePosition++];

   /* 选择了队列,现更新游标 */
   if (DequeuePosition >= TC_ENC_THREAD_POOL_QUEUE_SIZE)
    DequeuePosition = 0;

   while (!StopPending && GetWorkItemState (workItem) != WorkItemReady)
   {
    /* 等待数据到来 */
    TC_WAIT_EVENT (WorkItemReadyEvent);
   }

   /* 设置队列状态忙 */
   SetWorkItemState (workItem, WorkItemBusy);

   TC_RELEASE_MUTEX (&DequeueMutex);

   if (StopPending)
    break;

   /* 三种队列类型 */
   switch (workItem->Type)
   {
   case DecryptDataUnitsWork:
    DecryptDataUnitsCurrentThread (workItem->Encryption.Data, &workItem->Encryption.StartUnitNo, workItem->Encryption.UnitCount, workItem->Encryption.CryptoInfo);
    break;

   case EncryptDataUnitsWork:
    EncryptDataUnitsCurrentThread (workItem->Encryption.Data, &workItem->Encryption.StartUnitNo, workItem->Encryption.UnitCount, workItem->Encryption.CryptoInfo);
    break;

   case DeriveKeyWork:
    switch (workItem->KeyDerivation.Pkcs5Prf)
    {
    ….

    default:  
     TC_THROW_FATAL_EXCEPTION;
    }

    …
    continue;

   default:
    TC_THROW_FATAL_EXCEPTION;
   }

   if (workItem != workItem->FirstFragment)
   {
    SetWorkItemState (workItem, WorkItemFree);
    /* 数据处理完成,通知传输线程, 取走数据*/
    TC_SET_EVENT (WorkItemCompletedEvent);
   }

   if (InterlockedDecrement (&workItem->FirstFragment->OutstandingFragmentCount) == 0)
    TC_SET_EVENT (workItem->FirstFragment->ItemCompletedEvent);
}

PsTerminateSystemThread (STATUS_SUCCESS);
}

void EncryptionThreadPoolDoWork (EncryptionThreadPoolWorkType type, byte *data, const UINT64_STRUCT *startUnitNo, TC_LARGEST_COMPILER_UINT unitCount, PCRYPTO_INFO cryptoInfo)
{

/* 如果没有启动线程队列,则直接调用加密/解密算法 */
if (!ThreadPoolRunning || unitCount == 1)
{
   switch (type)
   {
   case DecryptDataUnitsWork:
    DecryptDataUnitsCurrentThread (data, startUnitNo, unitCount, cryptoInfo);
    break;

   case EncryptDataUnitsWork:
    EncryptDataUnitsCurrentThread (data, startUnitNo, unitCount, cryptoInfo);
    break;

   default:
    TC_THROW_FATAL_EXCEPTION;
   }

   return;
}

/* 把数据放入加密队列,等待加密操作完成 */
TC_ACQUIRE_MUTEX (&EnqueueMutex);
firstFragmentWorkItem = &WorkItemQueue[EnqueuePosition];

while (GetWorkItemState (firstFragmentWorkItem) != WorkItemFree)
{
   TC_WAIT_EVENT (WorkItemCompletedEvent);
}

firstFragmentWorkItem->OutstandingFragmentCount = fragmentCount;

while (fragmentCount– > 0)
{
   workItem = &WorkItemQueue[EnqueuePosition++];
   if (EnqueuePosition >= TC_ENC_THREAD_POOL_QUEUE_SIZE)
    EnqueuePosition = 0;

   while (GetWorkItemState (workItem) != WorkItemFree)
   {
    TC_WAIT_EVENT (WorkItemCompletedEvent);
   }

   …

   SetWorkItemState (workItem, WorkItemReady);
   TC_SET_EVENT (WorkItemReadyEvent);
}

TC_RELEASE_MUTEX (&EnqueueMutex);

TC_WAIT_EVENT (firstFragmentWorkItem->ItemCompletedEvent);

/* 等待加密完成 */
SetWorkItemState (firstFragmentWorkItem, WorkItemFree);
TC_SET_EVENT (WorkItemCompletedEvent);

/* data已经是加密后的数据 */
}

3 驱动设备

TrueCrypt内核会创建4种类型的设备:CDO, 磁盘过滤设备,卷过滤设备和磁盘设备。其设备类型的标示在设备的扩展结构中。

在内核驱动初始化时,根据具注册表中的参数决定本驱动是否创建卷过滤或者磁盘过滤设备:DriverObject->DriverExtension->AddDevice = DriverAddDevice

创建过滤设备的接口即是DriverAddDevice:

NTSTATUS DriverAddDevice (PDRIVER_OBJECT driverObject, PDEVICE_OBJECT pdo)
{
/* 卷过滤设备 */
if (VolumeClassFilterRegistered && BootArgsValid && BootArgs.HiddenSystemPartitionStart != 0)
{
   PWSTR interfaceLinks;
   if (NT_SUCCESS (IoGetDeviceInterfaces (&GUID_DEVINTERFACE_VOLUME, pdo, DEVICE_INTERFACE_INCLUDE_NONACTIVE, &interfaceLinks)))
   {
    /* 找到设备的Interface */
    if (interfaceLinks[0] != UNICODE_NULL)
    {    
     ExFreePool (interfaceLinks);

     return VolumeFilterAddDevice (driverObject, pdo);
    }

    ExFreePool (interfaceLinks);
   }
}

/* 磁盘过滤设备 */
return DriveFilterAddDevice (driverObject, pdo);
}

NTSTATUS VolumeFilterAddDevice (PDRIVER_OBJECT driverObject, PDEVICE_OBJECT pdo)
{

/* 获取设备栈顶层设备 */
attachedDeviceObject = IoGetAttachedDeviceReference (pdo);

DriverMutexWait();
status = IoCreateDevice (driverObject, sizeof (VolumeFilterExtension), NULL, attachedDeviceObject->DeviceType, 0, FALSE, &filterDeviceObject);
DriverMutexRelease();

ObDereferenceObject (attachedDeviceObject);

/* 加入设备栈 */
Extension->LowerDeviceObject = IoAttachDeviceToDeviceStack (filterDeviceObject, pdo);
…;

return status;
err:

return status;
}

DriveFilterAddDevice与VolumeFilterAddDevice 过程类同。

附录:

typedef struct EXTENSION
{
/* 设备类型 */
BOOL bRootDevice; /* Is this the root device ? which the user-mode apps talk to */
BOOL IsVolumeDevice;   
BOOL IsDriveFilterDevice;
BOOL IsVolumeFilterDevice;

ULONG lMagicNumber; /* To ensure the completion routine is not sending us bad IRP’s */

int UniqueVolumeId;
int nDosDriveNo; /* Drive number this extension is mounted against */

/* 操作参数 */
BOOL bShuttingDown;    /* Is the driver shutting down ? */
BOOL bThreadShouldQuit;   /* Instruct per device worker thread to quit */
PETHREAD peThread;    /* Thread handle */
KEVENT keCreateEvent;   /* Device creation event */
KSPIN_LOCK ListSpinLock; /* IRP spinlock */
LIST_ENTRY ListEntry;   /* IRP listentry */
KSEMAPHORE RequestSemaphore; /* IRP list request Semaphore */

HANDLE hDeviceFile;    /* Device handle for this device */
PFILE_OBJECT pfoDeviceFile; /* Device fileobject for this device */
PDEVICE_OBJECT pFsdDevice; /* lower level device handle */

CRYPTO_INFO *cryptoInfo; /* Cryptographic and other information for this device */

/* 磁盘属性 */
__int64 HostLength;
__int64 DiskLength;    /* The length of the disk referred to by this device */
__int64 NumberOfCylinders;   /* Partition info */
ULONG TracksPerCylinder; /* Partition info */
ULONG SectorsPerTrack;   /* Partition info */
ULONG BytesPerSector;   /* Partition info */
UCHAR PartitionType;   /* Partition info */
int HostBytesPerSector;

KEVENT keVolumeEvent;   /* Event structure used when setting up a device */

EncryptedIoQueue Queue;

/* 设备属性 */
BOOL bReadOnly;     /* Is this device read-only ? */
BOOL bRemovable;    /* Is this device removable media ? */
BOOL bRawDevice;    /* Is this a raw-partition or raw-floppy device ? */
BOOL bMountManager;    /* Mount manager knows about volume */

WCHAR wszVolume[TC_MAX_PATH]; /* DONT change this size without also changing MOUNT_LIST_STRUCT! */

// Container file date/time (used to reset date and time of file-hosted volumes after dismount or unsuccessful mount attempt, to preserve plausible deniability of hidden volumes).
LARGE_INTEGER fileCreationTime;
LARGE_INTEGER fileLastAccessTime;
LARGE_INTEGER fileLastWriteTime;
LARGE_INTEGER fileLastChangeTime;
BOOL bTimeStampValid;

PSID UserSid;
BOOL SecurityClientContextValid;
SECURITY_CLIENT_CONTEXT SecurityClientContext;

} EXTENSION, *PEXTENSION;

typedef struct
{
BOOL bRootDevice;
BOOL IsVolumeDevice;
BOOL IsDriveFilterDevice;
BOOL IsVolumeFilterDevice;

PDEVICE_OBJECT DeviceObject;
PDEVICE_OBJECT LowerDeviceObject;
PDEVICE_OBJECT Pdo;
int64 ConfiguredEncryptedAreaStart;
int64 ConfiguredEncryptedAreaEnd;

uint32 VolumeHeaderSaltCrc32;
EncryptedIoQueue Queue;

BOOL BootDrive;
BOOL VolumeHeaderPresent;
BOOL DriveMounted;

KEVENT MountWorkItemCompletedEvent;

CRYPTO_INFO *HeaderCryptoInfo;
BOOL HiddenSystem;

} DriveFilterExtension;

4 初始化过程总结

内核初始化阶段主要完成几个任务:

4.1 加载加密算法
4.2 加载64个32对数据加密/解密/子密钥创建对列(半同步/半异步模式)
4.3 根据配置创建磁盘过滤或者卷过滤设备
4.4 创建CDO

下部分(TrueCrypt 6.2a原理及代码分析(3~5))开始分析数据处理流程。(仅好友可见或者私有保留)

郑重声明:资讯 【TrueCrypt 6.2a原理及代码分析(2) – Raphael's Dairy】由 发布,版权归原作者及其所在单位,其原创性以及文中陈述文字和内容未经(企业库qiyeku.com)证实,请读者仅作参考,并请自行核实相关内容。若本文有侵犯到您的版权, 请你提供相关证明及申请并与我们联系(qiyeku # qq.com)或【在线投诉】,我们审核后将会尽快处理。
—— 相关资讯 ——