This article describes the scheme and implementation details of a driver for on-the-flight file encryption based on the file system minifilter approach. The descrided solution also provides per-process restriction of access to the encrypted files.
It is a good example of a development solution, which can be used to build data protection system. You can learn more about theย security technologiesย Apriorit develops for varios projects. Also take a look at ourย driver development competences.
Contents:
- Windows embedded encryption mechanisms. Advantages of the suggested system, compared to standard solutions
- Using minifilter drivers for files encryption
- General encryption scheme in minifilters
- Concept: two views of the encrypted file, encrypted and decrypted caches for it
- Idea implementation: redirector driver + virtual file system driver
- What is redirection and how it works
- Redirector tasks
- FS driver tasks
- Some insights into an implementation of the file system driver.
- Improvement: user-mode file system
Windows embedded encryption mechanisms. Advantages of the suggested system, compared to standard solutions
EFS (Encrypting File System) and Bitlocker are standard encryption solutions for Windows.
BitLocker provides full sector-level partition encryption. BitLocker driver (fvevol.sys) is located below the ntfs.sys driver in the file system stack. It automatically encrypts and decrypts data blocks written and read from the physical drive by NTFS. Thus, physical NTFS drive looks unencrypted, but if you try to read the raw data from it bypassing NTFS, you will receive an encrypted data [Win Internals 6th. Part2, Storage Management, page 173].
It should be noted that the safest BitLocker implementation provides encryption in the most effective way โ it uses Trusted Platform Module 1.2 cryptographic coprocessor, which exists in many modern PCs. BitLocker still can operate on PCs without TMP, but it requires connecting USB flash to load PC, or quitting hibernation mode (in this case the implementation doesnโt provide offline and reboot protection) [Win Internals 6th. Part2, Storage Management, page 164].
Obviously, this solution doesnโt allow to secure user data from malicious applications, running in the Windows environment, and also doesnโt prevent data leakage while transferring between applications and uploading to the Internet.
Encrypting File System (EFS) is a standard NTFS mechanism that provides encryption for separate parts of logical drive. The EFS functions transparently for applications. The EFS encryption is based on the specific account password. Data is being automatically encrypted and decrypted when accessed by applications running in the session of the user that has the permission to decrypt the data.
Thus, EFS also doesnโt allow to secure user data from malicious applications, running in the session of the user that has the permission to decrypt the data. And this mechanism doesnโt allow to prevent data leakage while uploading it to the Internet. To solve this issues, custom kernel driver needs to be developed. This will result in a solution that provides transparent encryption of file system selective objects.
Similarly to EFS, proposed solution will encrypt/decrypt data on access automatically. However, the advantage of this approach lies in the fact that data protection is brought to a user session level. It is provided by the system of rules that divide processes into permitted and prohibited ones. Thus, while reading data in the same user session, some applications will receive decrypted data, and other โ encrypted one.
Using minifilter drivers for files encryption
General principle of minifilter drivers and their connection to the drives
Operating principle of the file encryption system based on the minifilter driver lies in the fact that the driver connects to selected system partitions, including removable system drives, and filters/views all operations on the file system objects, which are located in these partitions.
Thus, no matter what file operation are performed by an application, minifilter driver will see it and will be able to change its parameters. For example, it can block opening of files or start of applications; redirect opening to another file; encrypt/decrypt or just check data while reading/writing it to the file.
Driver can save specific information for each partition, and then use it for each operation. For example, this feature can be used to set different encryption parameters for each partition. Driver can use different logic for each system partition.
Information that is specific to a partition or other file system object is located in the object called context.
The principle of the driver connection to a partition and architecture of minifilter driver are standard Windows minifilter framework functions. Thus, these driver types are used by other software, for example, antiviruses.
By varying parameters of the driver connection to a partition, we can make so that antivirus drivers, which are also connected to the partition, could receive encrypted data.
To filter file operations, minifilter driver registers callbacks for each file system operation. These callbacks are called by the system when the specific operation runs.
General encryption scheme in minifilters
Without per process access restriction
To start encryption mini-filter driver development, we need to understand the general encryption scheme, employed in the solution and how connecting to read/write handlers works.
To encrypt user data, minifilter driver has to register read/write handlers โ IRP_MJ_READ and IRP_MJ_WRITE, respectively. It can be performed by standard methods provided by the framework.
There are several read/write operation types in file systems:
- Cached read from file โ file system driver reads data from cache. If cache has no data, Cache Manager reads the data from file to the cache, and then returns read data to file system.
- Paging IO read โ file system driver reads data directly from drive. If this operation is initiated by Cache Manager, then the data is moved to ัache for file, and if it is initiated by application, than the data is not moved to the cache for file.
- Fast IO read โ data is read directly from cache, and IRP is not created.
- Cached write to file โ data is written to ัache. Cache Manager doesnโt guarantee that data is going to be written to file on drive at once.
- Paging IO write โ data is written directly to the file on a drive. If this operation is initiated by Cache Manager, than flush takes place, and if it is initiated by an application, than data is written to the file and not moved to the cache.
- Fast IO write โ data is written directly to cache, bypassing file system.
Cache Manager usually uses paging IO read/write operations to read data to the cache or flush data from the cache to the file. Thus, after Paging IO reading, data is moved to cache, and after Paging IO writing, data is written directly to the file on the drive.
NOTE: According to experience of working with minifilter, and file system filter driver for encryption, there always should be decrypted data in cache. Otherwise, there are use cases, when application can receive both encrypted and decrypted data at the same time.
For example, if there is encrypted data in cache and application has performed file mapping, then application will refer directly to cache region, where data from the file is located. Therefore, minifilter wonโt receive and decrypt read operations. To handle this case, hooks on Nt* functions are used in file system filter drivers for x86 architecture. But this approach is forbidden for Windows x64 systems.
After connecting to a partition and registering handlers (IRP_MJ_READ and IRP_MJ_WRITE), minifilter driver sees all above operation types (except for FastIO). But minifilter data encryption for each Paging IO write from Cache Manager and decryption for each Paging IO read from Cache Manager is enough to implement common transparent file encryption without per process access restriction.
Thus, there will always be decrypted data in all applications and cache, and there will always be an encrypted data in the file on a drive.
Scheme complication in case of per process access restriction
Process access restriction makes on-the-fly file encryption driver development more complicated. User session data security means that only limited range of applications has access to decrypted data. Other applications should receive encrypted data while trying to read it from file.
Thus, the logic of data encryption/decryption by minifilter becomes more complicated.
The simplified scheme of actions that should be performed by minifilter:
- Cached read requested by blocked application.
- Cached read requested by allowed application.
- Non-cached read by blocked application.
- Non-cached read by allowed application.
While handling operations in minifilter, it is determined whether the process is allowed or blocked. In order to do it, context tied to each FileObject can be used. This context is created in a handler on the open/create file operation. At this moment the process that opens the target file is clearly known. Information about process can be stored in this context. The context can be removed during the FileObject close operation.
NOTE: There is one very important characteristic in the work of Cache Manager. It is the fact that Paging IO operations for a file can be performed in the context of any system process, including processes that are not related to the file. These operations are usually performed by the SYSTEM service process. Cache Manager uses one of the opened FileObjects to a file and all Paging IO operations are performed to this FileObject. In this case, the FileObject context serves to receive information about process, which opened the file and therefore worked with it.
Also, it will be important to use Per-file contexts.
NOTE: For architecture of minifilters for OS older than Windows Vita, these contexts are implemented via Per-Stream contexts.
As it follows from the name, this context is directly linked to the file on a drive, regardless of the amount of opened FileObjects. For all FileObjects, opened for the specific file, this context is the only one, and it can be received via any FileObject. This context will be removed by the system when the last FileObject is closed.
NOTE: Per-file context is related to the FCB structure in the file system encryption driver, and as this structure exists until any opened FileObject exists, than the context does too.
Such information as, for example, whether the file is encrypted, its decrypted size, file modification flag, and other data that is used for encryption implementation will be stored in this context.
Problems with this solution architecture
File encryption driver development using the minifilter approach has one big disadvantage, that inexperienced developer may be not aware of it.
While using file mapping, processes that are forbidden to decrypt the file still have access to decrypted data of this file. It happens because in case of file mapping application gets access directly to section of cache, where the file view is. Thus, minifilter cannot detect file mapping operations. Without making changes to encryption solution architecture, this problem can be solved by using file mapping functions hooks. In x64 OS, it can be only user mode hooks. This approach involves processes, and it is not native and leads to a large number of potential application problems, which are very difficult to foresee. It is getting more complicated by imperfection of hook engines available for now and the necessity to consider a huge amount of nuances with hook implementation.
The most native solution for an OS (in terms of design) uses custom minifilter driver together with custom file system driver.
Concept: two views of the encrypted file, encrypted and decrypted caches for it
General principle of cache involvement in the work of an application
When application reads data from the file, in case of the regular cached read, this data is taken from a cache by the file system. If there is no target data in the cache, then at first this data is placed to the cache, and then the file system returns it to the application. In case of the regular cached write, data is written to the cache by the file system, and then at some point Cache Manager flushes this data to the drive.
When an application uses file mapping to work with the file, it gets access directly to cache sections, where the view of this file is located. Another application can open this file at the same moment and perform cached operations with it. In this case, both applications have access to the same file view in cache. Thus, if one application is allowed and another one is not, then the forbidden one will also have access to decrypted data. You can avoid data leak by using user mode hooks, as mentioned above. In hooks it is necessary to implement particular logic for forbidden applications working with filemapping. This logic will allocate its memory section and place encrypted data there, and then return this section to the application.
Cache division for allowed and forbidden applications
Another architecture is possible, where file view for allowed and forbidden applications is divided into two separate views for each of the types of applications. It is possible only if one view matches one file on the drive, and another view matches another file. Therefore, two different files must exist, but all applications should see only one file in its original location. For allowed applications, all requests should be redirected to another (decrypted) file, which is located elsewhere on the drive.
Diagram. No redirection to decrypted file for forbidden application
Diagram. Operations redirection to decrypted file for allowed application
In OS Windows architecture, โinvisibleโ redirection of requests from one file to another is implemented via minifilter drivers. In this approach, minifilter driver intercepts specific operation and โinvisiblyโ redirects it to another file. However, for data security purposes, it is unacceptable to store decrypted file on a drive. Thatโs why this file can be stored on the drive in encrypted way and be decrypted during read/write operations.
Storing two identical files is extremely inconvenient, because these two files should be constantly synchronized, and user can simply remove the file mistaking it for a duplicate of the original file, or simply an unknown file.
It is possible to eliminate the need to use the second file on the drive by adding special file system driver to the solution architecture. This driver is mounted like ordinary separate local drive and behaves accordingly: it displays files and lets you access them. But it is a virtual logical drive, so it reads files from any other catalogue on another local drive. In this solution architecture, this driver accesses original encrypted user file on the drive. The word โaccessโ means that driver displays this file on its local drive, and for each file operation performs the same one to the original file. But in this case, the driver will decrypt and encrypt the read/write operations to the original file. Thus, if an application was redirected to this driver, it would receive decrypted data from files, which are displayed by this driver.
Diagram. Redirection of the original file access to the file system driver
Idea implementation: redirector driver + virtual file system driver
As shown on the diagram, minifilter driver, which redirects specific file accesses, and file system driver, which receives redirections, should be used to implement the idea. It turns out that, when the application accesses any file, this operation can be โimplicitlyโ redirected to another file.
What is redirection and how it works
Before performing read/write operations, it is necessary to open first the file. Redirection of the file access consists of the following: minifilter driver views file opening operations and redirects them to another file via standard mechanisms for the file system filters. Then all further operations in the file opening-closing session are automatically performed with file, which has been redirected to, and therefore performed through the file system driver, which has been redirected to.
Redirector tasks
Redirector must intercept open file operations and detect if this file is encrypted and if application is allowed to decrypt it.
If the file is encrypted and an application is allowed to decrypt it, then redirector driver redirects file opening to the file system driver.
FS driver tasks
FS driver provides standard file system features, though it does not works directly with data on a physical drive, but reads and writes data to another file on any other partition. It means that, via standard API for working with files in kernel mode, FS driver performs file operations received from application with that file. This driver is a virtual volume device, thus, it should be mounted just like a volume device. However, the driver shouldnโt assign a drive letter to the volume device, so that user couldnโt have a direct access to this volume from applications.
The driver should display the decrypted file to the application, therefore, a logic that decrypts/encrypts data during read/write to file and allows to display the file of correct size to application should be implemented in it.
Displaying a correct file size is an important feature of this driver, because the size of the encrypted file can differ from the size of the decrypted one.
NOTE: For an easier handling of the encrypted file, header is usually added. It results in the necessity of bias control during read/write operations to encrypted file in the driver.
Some insights into an implementation of the file system driver.
Building a driver on the basis of FASTFAT
WDK provides examples of encryption file system driver development using FASTFAT. This driver can become a basis for the driver of file system of solution architecture described above.
It is necessary to leave FS logical objects (FCB, CCB structures) management layer, as well as cache, shared access to the file, and OpLocks management in the driver. Layer that manages files and directories data directly on the physical drive, everything concerning dirent, and all driver operations sent to devices that are placed below it in the file system stack, should be removed.
Since the driver collects data from another file on the logical drive, it should include logic that opens this file when open request comes from application and keeps this file opened until close request comes to the driver.
According to the โdriver should display decrypted fileโ rule, the following logic should be added to the driver:
- data encrypting/decrypting during non-cacheable read/write operations;
- during file size specifying and obtaining operations, correcting the size so that the driver would specify encrypted data size as the file size, and return the decrypted data size.
In order to make this logical drive inaccessible to other applications, you shouldnโt inform Mount Manager about device during its mounting.
Redirector driver needs to know the native path ะพf the volume device in order to redirect operations to virtual logical drive. Thatโs why the file system driver should inform redirector driver about this path. To this end, it is necessary to create a control device in the file system driver, through which it would be possible to request the name.
Improvement: user-mode file system
File system driver can be improved so that the processing of every requested operation is performed in the user mode service. In order to do this, commands containing parameters and returning results should be send between the service and the driver.
NOTE: such data exchange can be organized via the Inverted Call Model mechanism that is well-described by OSR. Using this mechanism, on each file system operation, which comes from an application, driver sends a specific command corresponding to this operation to the service. Together with this command, driver will send all these operation parameters and wait for the results return by the service. Then the driver will send this result as the result of processing of operation requested by an application. Using all operation parameters, which were sent by the driver, service performs needed actions and returns the result to the driver. This architecture is an analogue to FUSE, which is used in Unix-like systems.
Such improvement allows to move all operations processing to user-mode and avoid developing kernel-mode code. This makes changing of operation processing logic more flexible and fast.
Improvement also allows:
- using released encryption libraries;
- storing keys on protected servers;
- validating digital signatures;
- using graphical interface;
- using different programming languages;
- bringing logic to dll and update it without system rebooting;
- storing files in cloud storages.
As such, every possible opportunity that user-mode applications have are left opened.
Take a look at a tutorial on File System Filter Drivers in our blog.
Read a tutorial on Virtual Disk for Windows and get code sources.