+
74
-

回答

是的,Windows 提供了这种机制。这正是商业级“透明加密软件(DLP)”的底层实现方式。

根据实现的层次(内核态 vs 用户态)和难易程度,主要有以下三种 SDK/API 方案可供选择:

方案一:Minifilter 驱动(内核态,最正统、最难)

这是所有防泄密软件(如各种“加密狗”、企业安全软件)的标准做法。

API/SDK: Windows Driver Kit (WDK) - File System Minifilter Drivers

原理:

你在操作系统内核层编写一个驱动程序(.sys)。

注册回调函数拦截 I/O 请求(IRP)。

读取时 (IRP_MJ_READ): 拦截读取请求,驱动在内核中读取硬盘上的密文 -> 解密 -> 将明文填充到内存 buffer 返回给上层应用(如记事本)。应用层完全不知道文件被加密了。

写入时 (IRP_MJ_WRITE): 拦截写入请求,获取应用层传来的明文 -> 加密 -> 写入硬盘。

优点: 全局生效,支持所有软件,用户体验完美(无感),支持内存映射文件。

缺点:

开发难度极高: 必须用 C/C++ 开发,涉及复杂的内核内存管理。

风险大: 代码写错一行,电脑直接蓝屏(BSOD)。

门槛高: 驱动必须购买昂贵的 EV 证书签名,否则 Windows 拒绝加载。

Python 不可做: Python 无法直接编写内核驱动。

方案二:ProjFS (Windows Projected File System)(用户态,官方现代方案)

微软在 Windows 10 (1809+) 引入的原生功能,用于实现类似 Git VFS 的功能。

API/SDK: ProjFS API (支持 C++, C#)

原理:

你创建一个“投影根目录”(Virtualization Root)。

当用户在这个目录下打开文件时,Windows 会向你的程序请求数据(Provider)。

你的程序从数据库或加密文件中读取数据 -> 解密 -> 提供给 Windows。

Windows 会把这些数据呈现为“真实文件”。

优点: 微软官方支持,运行在用户态(User Mode),比驱动稳定,不会导致蓝屏。

缺点: 主要是为了“读”设计的(按需加载),对于“写”(自动加密回写)的支持逻辑比较复杂,需要处理“脏数据”回调。

方案三:Dokan / WinFSP (用户态文件系统,最适合 Python)

这是 Linux FUSE (Filesystem in Userspace) 在 Windows 上的对应实现。这是目前唯一能让你用 Python 实现“挂载盘动态加解密”的可行方案。

SDK: WinFSPDokan

原理:

你的 Python 脚本利用库创建一个虚拟盘符(例如 Z: 盘)。

映射: 你将硬盘上的 D:\EncryptedData 映射到 Z:。

拦截:

当用户打开 Z:\a.txt 时,你的 Python 函数 read() 被调用 -> 读取 D:\EncryptedData\a.txt -> 解密 -> 返回明文。

当用户保存 Z:\a.txt 时,你的 Python 函数 write() 被调用 -> 收到明文 -> 加密 -> 写入 D:\EncryptedData\a.txt。

优点:

可以用 Python 开发: 有现成的 winfsp 或 dokan-python 绑定。

完全透明: 用户看到的 Z: 盘全是明文,硬盘上的源文件全是密文。

开发简单: 不需要写驱动,像写普通的文件读写逻辑一样。

推荐:使用 Python + WinFSP 实现

如果你想用 Python 实现你描述的功能,WinFSP 是最佳选择。你需要安装 WinFSP 驱动,然后使用 Python 库 winfsp。

下面是一个概念验证代码(需要先安装 WinFSP 和 pip install winfsp):

注意:此代码仅为逻辑演示,展示如何拦截读写。

import os
import sys
# 注意:你需要安装 winfsp 的 python 绑定
# pip install winfsp
from winfsp import FileSystemBase, FILE_ATTRIBUTE_DIRECTORY

class TransparentEncryptFS(FileSystemBase):
    def __init__(self, target_path, encryptor):
        super().__init__()
        self.target_path = target_path # 实际存储密文的物理路径
        self.encryptor = encryptor     # 你的加解密类

    def _real_path(self, path):
        # 将虚拟路径 /file.txt 转换为物理路径 D:/Encrypted/file.txt
        if path.startswith("/"):
            path = path[1:]
        return os.path.join(self.target_path, path)

    def get_file_info(self, path):
        # 获取文件信息,如大小、时间
        full_path = self._real_path(path)
        try:
            st = os.stat(full_path)
            # 注意:如果是加密文件,文件头部可能有 header,
            # 这里报告的文件大小应该减去 header 的长度,否则记事本会读到乱码
            real_size = st.st_size
            if not os.path.isdir(full_path):
                 # 假设 header 长度 13
                real_size = max(0, st.st_size - 13) 

            return {
                "file_attributes": 0x10 if os.path.isdir(full_path) else 0,
                "file_size": real_size,
                "creation_time": int(st.st_ctime * 10000000 + 116444736000000000),
                "last_access_time": int(st.st_atime * 10000000 + 116444736000000000),
                "last_write_time": int(st.st_mtime * 10000000 + 116444736000000000),
            }
        except FileNotFoundError:
            raise

    def open(self, path, create_options, granted_access):
        # 打开文件句柄
        full_path = self._real_path(path)
        try:
            fd = os.open(full_path, os.O_RDWR | os.O_BINARY)
            return fd
        except FileNotFoundError:
            raise

    def read(self, path, file_context, offset, length):
        # 核心:拦截读取
        # 1. 移动文件指针到物理文件的对应位置 (+header长度)
        os.lseek(file_context, offset + 13, 0) # 假设跳过13字节头

        # 2. 读取密文
        encrypted_data = os.read(file_context, length)

        # 3. 实时解密 (这里是流式解密,AES-CTR 或 XOR 比较适合,AES-CBC 很难做随机读取)
        decrypted_data = self.encryptor.decrypt_block(encrypted_data)

        return decrypted_data

    def write(self, path, file_context, buffer, offset, write_to_end):
        # 核心:拦截写入
        # buffer 里是明文

        # 1. 实时加密
        encrypted_data = self.encryptor.encrypt_block(buffer)

        # 2. 写入物理位置 (+header长度)
        os.lseek(file_context, offset + 13, 0)
        os.write(file_context, encrypted_data)

        return len(buffer)

if __name__ == "__main__":
    # 挂载 D:\MySecret 到 Z: 盘
    fs = TransparentEncryptFS("D:\\MySecret", my_encryptor)
    fs.mount("Z:") 
    print("Z: 盘已挂载,里面的文件是自动解密的")

总结

如果你是开发商业软件:请招聘 C++ 驱动开发工程师,使用 Minifilter

如果你是个人使用或 Python 开发者:请使用 WinFSP。它能在“我的电脑”里挂载出一个 Z 盘,你在 Z 盘里看到的是明文,但实际写入硬盘(D盘某文件夹)的是密文。

这实现了真正的“打开即解密,保存即加密”,而且记事本等软件无需做任何修改。

网友回复

我知道答案,我要回答