Encryption driver + NTFS compression

Dear NTFSD members,

my encryption filter encrypts/decrypts files and filenames on removable drives.
No filesize changes.
Everything work fine on FAT (or at least I can’t find any bugs) but not on NTFS. The following bug I can always see on NTFS volume with compression:
I’m trying to copy 1000 files to removable drive. 1-3 of this files becomes bad after this operation (not the whole file, but a small part of it, with 32768 size).
With debug output I can see, that the content of this broken files was correctly encrypted.

Please take a look on this part of code, I did try a lot of ways, read this forum but…
You are the latest hope-)

case IRP_MJ_WRITE:
{
CMyCryptorFolder* pFolder;
PVOID pvBuffer;
ULONG dwLength;

pFolder = GetFolderFromFileObject(pFileObject);
if (pFolder == NULL)
break;
if (IsFolderFileObject(pFileObject))
break;

if (!(Irp->Flags & IRP_NOCACHE) && !(Irp->Flags & (IRP_PAGING_IO | IRP_SYNCHRONOUS_PAGING_IO)))
break;

if (Irp->MdlAddress)
{
PMDL MdlNext;
ULONG cbMdl;

__try
{
dwLength = 0;
MdlNext = Irp->MdlAddress;

while (MdlNext != NULL)
{
pvBuffer = MmGetSystemAddressForMdlSafe(MdlNext, NormalPagePriority);
cbMdl = MmGetMdlByteCount(MdlNext);

pFolder->CryptData(pvBuffer, cbMdl);
MdlNext = MdlNext->Next;
}
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
break;
}
}
else
{
dwLength = pIoStackLocation->Parameters.Write.Length;
if (Irp->AssociatedIrp.SystemBuffer != NULL)
pFolder->CryptData(Irp->AssociatedIrp.SystemBuffer, dwLength);
else if (Irp->UserBuffer != NULL)
pFolder->CryptData(Irp->UserBuffer, dwLength);
}

IoCopyCurrentIrpStackLocationToNext(Irp);
IoSetCompletionRoutine(Irp, WriteFileComplete, pFolder, TRUE, TRUE, TRUE);

return IoCallDriver(deviceExt->FileSystem, Irp);
}

NTSTATUS WriteFileComplete(PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID Context)
{
PIO_STACK_LOCATION pIoStackLocation = IoGetCurrentIrpStackLocation(Irp);
PMDL MdlPrev, MdlNext;
CMyCryptorFolder* pFolder = (CMyCryptorFolder*) Context;
PVOID pvBuffer;
ULONG cbMdl;

if (Irp->MdlAddress == NULL)
{
ULONG dwLength = pIoStackLocation->Parameters.Write.Length;

if (Irp->AssociatedIrp.SystemBuffer != NULL)
pFolder->CryptData(Irp->AssociatedIrp.SystemBuffer, dwLength);
}

MdlNext = Irp->MdlAddress;
while (MdlNext != NULL)
{
pvBuffer = MmGetSystemAddressForMdlSafe(MdlNext, NormalPagePriority);

cbMdl = MmGetMdlByteCount(MdlNext);
pFolder->CryptData(pvBuffer, cbMdl);

MdlNext = MdlNext->Next;
}

if (Irp->PendingReturned)
IoMarkIrpPending(Irp);

return Irp->IoStatus.Status;
}

xxxxx@unispy.com wrote:

Dear NTFSD members,

my encryption filter encrypts/decrypts files and filenames on removable drives.
No filesize changes.
Everything work fine on FAT (or at least I can’t find any bugs) but not on NTFS. The following bug I can always see on NTFS volume with compression:
I’m trying to copy 1000 files to removable drive. 1-3 of this files becomes bad after this operation (not the whole file, but a small part of it, with 32768 size).
With debug output I can see, that the content of this broken files was correctly encrypted.

As far as my research has found, through a thorough analysis of the NTFS
assembly, implementing encryption on a compressed ntfs volume does not
work. NTFS does not support encryption and compression on the same set
of files and it has been ‘recommended’ to me from MSFT devs to do the
same. From what I have been able to figure out, NTFS caches the
compressed data on the non-cached IO path. Because of this, there are
scenarios where data gets corrupted if you are a filter sitting above
NTFS implementing encryption.

Pete


Kernel Drivers
Windows File System and Device Driver Consulting
www.KernelDrivers.com
866.263.9295

Peter, thank you very much, it’s a valuable information.

> same. From what I have been able to figure out, NTFS caches the

compressed data on the non-cached IO path.

Yes, for compressed files, NTFS always uses the cache.

The cache is cleartext, and the IO below cache (paging IO) uses the temporary buffers to contain the compressed data. Reads go the way: disk to tmp buffer, then decompress from tmp buffer to cache pages, then from cache pages to the app.


Maxim S. Shatskih
Windows DDK MVP
xxxxx@storagecraft.com
http://www.storagecraft.com