一、概述
加密是最常见的数据安全保护技术,在数据生命周期各阶段均有应用。从应用场景和技术实践上,按加密对象、用户是否感知、加密算法等维度,有多种分类及应对方案,并在主流操作系统如Windows、Linux、Android中有广泛应用。
本文是Linux内核安全技术系列第二篇,主要介绍磁盘加密技术及主流实例。首先介绍磁盘加密技术背景,包括应用场景、威吓模型、技术线路分类等;其次介绍磁盘加密的两种实例,即全盘加密FDE和文件系统加密FBE,重点介绍Linux系统和内核主流FBE实例;最后以eCryptfs为例,详细分析其原理和应用。
【资料图】
Linux内核安全技术系列第一篇:Linux内核安全技术——开源演进回顾
1.1、说明
数据在其生命周期各阶段的信息安全风险有很多,如假冒、盗改、泄漏、越权访问、DoS拒绝访问等,一些成熟的方法通常能够解决消除多种风险。本文主要介绍磁盘加密技术,主要注意的是数据泄露、机密性维数,其他维数风险和保护不过多涉及。
1.2、简要术语和术语
本文使用的缩略语和技术语说明如下:
二、技术背景介绍
2.1、威胁模型
数据生命周期管理(Data Lifecycle Management)通常将数据计划分为生产、存储、使用、分享、销售、归档几个阶段。并从信息安全维护度,则一般将数据规划分为三种状态,即:Data in使用、移动/传输中的数据、静态数据。
Data in Motion/Transit,即数据传输场景,是大家最熟悉、技术发展最成熟的安全场景。例如基于SSL/TLS协议的Https应用,基于SSH协议的SCP/SFTP应用等。这些技术对数据的安全保护不只是包加密传,也包含双向身份证明、完整性保护等。
Data in Use,即数据使用场景。此时数据存储在系统DRAM、Cache、CPU Register中,一般明文存在。但在一些高安全场景下,为防止侧面信息攻击(如Cold开机攻击获取DRAM中键信息),业界也提出了Full Memory Encryption全内存加密技术。如Intel的TME(Total Memory Encryption)、AMD的SME(Secure Memory Encryption)等。FME使能时系统DRAM数据全部为加密存储,C PU通过特定硬件加解密引诱分离在读数据时做解密加密操作,加解密解密一般每次开机时一次生成。
Data at Rest,即数据(保持持久化)存储场景。此时数据属于非活动状态未使用,存储在磁盘等非易失性。安全风险主要有非授权访问、设备丢失导致数据泄漏等。常见保护方式包括物理/网络层面的隔离和访问控制、以及数据(落盘)加密。对于加密存储的磁盘数据,即使设备(如PC/手机)失败,攻击者拆出硬盘或Flash工具,也只能读取到器具中的密文,保证密钥数据机密性。
2.2、技术路线
加密是防止数据泄漏、保证机密性的有效手段。按照不同维数,加密技术/方案可以有多种分类,简单汇总如下:
需要说明的是,几种方案互不相干,一种方案通常符合/多种特征/技术。例如本文要介绍的磁盘加密技术磁盘加密,其加密对象一般是整个磁盘或文件系统,但来自数据状态维度看属于数据加密技术,从用户维度看属于透明加密技术,从加密算法维度看采用加密技术。
下面简单介绍分类几个涉及的技术概念/术语,详情可查阅文末参考链接,及后续章节中的详细分析。
静态数据加密数据在静态状态下保持加密的技术,参考https://wiki.archlinux.org/title/Data-at-rest_encryption说明,加密对象一般为磁盘(块设备)、文件系统目录,加解密过程采用透明加密技术。
透明加密透明加密,也称为实时加密或即时加密。特点是数据在使用过程中自动完成加解密,消耗用户干预。
三、磁盘加密技术
如上节所述,磁盘加密磁盘加密,目标是保护静态下的数据的机密性,加密对象是整个磁盘/分区、或者文件系统,采用实时加解密技术。更多介绍可参考https://en .wikipedia.org/wiki/Disk_encryption 。
磁盘加密技术从加密对象、软硬件实现、文件系统特征等维度,也可以有多种分类。 首先,根据加密对整个市场的影响磁盘,还是文件系统,可分为全磁盘加密和文件系统级加密(也称为基于文件的加密)两大类。
3.1、FDE
全盘加密全盘加密在实现上有硬件、软件两种方案。两者核心原理类似,区别是加解密核心功能所在主体是软件还是硬件,其它软件解决方案不能真正加密整个硬盘(启动分区一般不加密) ),而硬件方案基于硬件的全盘加密则具备整个硬盘加密能力。硬件FDE方案主要产品是自加密硬盘自加密硬盘,一般由内存组成零部件厂商、安全厂商提供。关于硬件 FDE 方案和 SED 产品技术,可参见文末基于硬件的全磁盘加密和 SED 相关链接。
硬件和软件FDE方案核心原理及流程类似,统一抽像说明如下:
在初始化或FDE时,会随机创建一个磁盘数据加密DEK(磁盘加密密钥,用户无权限),同时要求用户输入一个AK(身份验证密钥)用于加密保护DEK。在使用时,需用户先输入AK验证并破解DEK,其后操作系统才能使用DEK访问加密码盘上的数据。下图是一个软件FDE的描述。
由于需执行特定程序展示UI提供用户输入AK并验证,故这部分启动代码不能加密。引出了相应的Pre-Boot Authentication及PBA环境的概念。
在PBA实现上,硬件FDE方案(SED产品)一般出厂时内嵌Pre-Boot环境(小型操作系统或bootloader),上电后先运行Pre-Boot程序并验证AK,再进行正常的加载引导等。
软件FDE方案采用不加密启动分区的方式,一般在初始ramdisk集成PBA功能并验证完成。
软件FDE方案发展历史之久,主导OS环境成熟方案,例如Windows下的BitLocker、Apple OS/X下的FileVault、以及Linux/UNIX生态下的dm-crypt/LUKS。另外也有不依的赖操作系统的第三方FDE方案,如TrueCrypt、VeraCrypt等。更多软件FDE方案可以参考链接https://en.wikipedia.org/wiki/Comparison_of_disk_encryption_software及下图。
对Linux下dm-crypt/LUKS方案感兴趣的同学可以在Ubuntu虚拟机上测试研究。下面是几个关键场景截图:Ubuntu虚拟机安装时使能磁盘加密配置、启动阶段PBA验证、系统主分区sda5加密后的磁盘类型(可看到boot分区sda1未加密)。
3.2、FBE
File-Based Encryption,又称文件系统级加密,文件系统加密。相比于FBE,第二个名字更能体现基于文件系统的技术特点的方案。而基于文件系统的特点,涉及决定了只能由软件实现,其他方面决定了各个方案的差异也主要围绕在文件系统中。
常见FBE方案,一般分为Stackable cryptographic filesystem 和Native/General filesystem with encryption两种。
第一个,新增一个加解密文件系统,包含在现有存储软件栈的相关层。例如Linux内核自v2.6.19开始支持,已经很成熟稳定的eCryptfs方案,就是在VFS ->Native FS层其中加入新加解密文件系统支持。类似还有基于用户状态文件系统FUSE的各种方案。
第四,在现有文件系统中引入加解密功能。例如Linux内核自v4.1支持的Ext4文件系统加密,自v4.2支持的F2FS文件系统加密,自v4.10以后支持的UBIFS文件系统加密。需要说明的是,内核中Ext4、F2FS、ubifs共享加解密功能模块,即内核fscrypt特性。另外,Android系统引入的FBE方案,底层内核实现同样基于F2FS+fscrypt。
两种类型及更多行业FBE现实,可参考链接https://en.wikipedia.org/wiki/List_of_cryptographic_file_systems 及下图:
和FDE方案相比,FBE有几个表现着的特点:
1、支持单一的目录或文件加密,方方便使用配置。只加密目标对象,不加密整磁盘,降低了系统加解密载营销。
2、支持不同目录/文件使用不同加密匙。
3、加密目录和非加密目录并存(甚至一个加密目录中加密和非加密文件也可以并存)。加密目录文件的备份传输灵活方便。
更多FDE和FBE的详细对比,以及Linux中FBE具体实现,请参看后续章节。
3.2、FDE与FBE
前面分析已经知道,软件FDE和FBE都是基于文件系统,差异主要是在文件系统实际出现差异,整理比较如下:
【说明】软件FDE/FBE主要是指其加解密功能主体在软件(文件系统)实现,并不意味着不使用硬件,而是为了提高性能,另外利使用类似Crypto Engine等硬件引擎来加速。
从整个系统软件硬件结构分析,可将硬件FDE、软件FDE、以FBE现实和系统软件硬件结构的相关位置描述如下图:
上层用户,磁盘加密方案,越往上层用户实现使用配置越灵活,但性能较差;越往下层实现越不灵活,但对越透明且性能很好。结合前面的文字描述,将FDE和FBE两种方案的差异对比整理如下:
3.3、Linux系统FBE
从Linux系统软件架构看,典型的FDE和FBE实例分发如下图,包括基于dm-crypt的软件FDE方案、基于通用文件系统的fscrypt FBE方案、基于VFS的eCryptfs FBE方案,以及众多基于FUSE的FBE方案。
前面章节已经简单介绍了基于dm-crypt的FDE方案在ubuntu虚拟机上的试验情况,这里先简单介绍Linux系统和内核的几种软件件FBE实例和特殊点,后续章节会以eCryptfs为例子做详细分析。
基于保险丝的
FUSE即Filesystem in Userspace,用户状态文件系统。FUSE设计初衷就是为方便用户不修改编译内部的情况下,在用户空间实际制定文件系统。FUSE架构原理和实际如下图,内核状态FUSE和用户状态libfuse为App –>VFS ->用户文件系统链接服务,用户定义实现主要在用户级文件系统部分。
由于自然的生命力,基于FUSE实践发现FBE的方法有很多,例如gocryptfs、EncFS、CryFS、securefs等。但是,FUSE引入的多次系统调用和选择性开发,也导致基于FUSE的FBE方案通常性能不佳好gocryptfs项目项目有个个个个个f f f各各各链接链接链接链接链接https://nuetzlich.net/gocryptfs/comparison/)
首先是各种stackable FBE方法介绍和整体特点,从数量上看,FUSE FBE方法占绝大部分,非FUSE方法只有eCryptfs。
其次,相对于eCryptfs,FUSE方案在性能上整体处于优势。尽管gocryptfs在顺序读上性能不会出错,但在其他测试如解压、MD5计算、目录递归访问/删除等测试项上看,功势也比较明示。这和我们在3.2章节比FDE和FBE、以及分析磁盘加密在软件栈不同层实际现在的效果差异是一样的。
更多关于FUSE FBE各方案的特点,如文件内容加密、文件名加密等,可参考上述各对比链接或方案主页,在此不详细介绍。
eCryptfs
eCryptfs衍生于Cryptfs项目,早期方案和设计思想源自2005和2007的两篇论文,即《eCryptfs: an enterprise-class cryptographic filesystem for Linux》和《eCryptfs: a Stacked Cryptographic Filesystem》。目分成内核部分和用户状态部分,内部状态代码于v2.6.19版本结合进入社区主线,用户状态代码在软件包ecryptfs-utils中维护。
eCryptfs 和上面介绍的 FUSE 方案一样,也属于 stackable FBE 类型,故不依赖于 OS 底层文件系统类型,可以在各种文件系统之上查看,灵活很好。也支持对不同文件、目录加密,以及文件名加密。
目前eCryptfs项目社区开源活跃度不高,早期用户/产品不断迁移,但其方案和设计原理仍然值得深入学习分析。详细详细测试验证和原理分析请见第4章。
加密文件
fscrypt 是在内核文件系统上实现的一个原生 FBE 方案。fscrypt 特性还包括内核态和用户态两个部分,内核态部分是在 fs/crypto 目录的实现公共使用加解密模块,支持ext4、F2FS、UBIFS文件系统集合使用。使用用户状态工具fscrypt则现实各种命令行工具方使用。
fscrypt作为FBE方案,支持不同目录/文件采用不同密钥,对于元数据,fscrypt支持文件名文件名加密,其他元数据如时间戳、大小、属性等不加密。大的应用即Android采用的FBE方法,结合F2FS文件系统,对手机上的数据进行静态数据加密保护。本文受限于篇幅,不做详细分析。
四、eCryptfs详解
本章节我们先用简单的例子验证eCryptfs加密效果特点,使大家对方案有一个整体的认知,同时也提供一个C版本本示例作参考。其次测试对结果进行初步分析,接着详细分析eCryptfs方案架构原理和核心机制,最后对关键业务流程代码进行简单梳理。
测试使用环境Ubuntu 20.04虚拟机,因Ubuntu系统默认打开eCryptfs内核配置(CONFIG_ECRYPT_FS=y),只需apt安装用户态工用ecryptfs-utils即可。
4.1、测试用例
下图是一个脚本基础测试用例。先创建测试目录和文件hello,之后使用mount -t ecryptfs方式对测试目录进行加密,以免免命令行交际,将所有加密参数(passwd、cipher、key size等)通过命令行-o传递。加密后在测试目录创建新文件hello_encrypted。最后umount取消目录加密。
从第一个测试用例可以观察到的现像/特性有:
1、执行mount,写入hello_encrypted文件内容后可以正确访问,但umount后则为密文。说明eCryptfs作为堆集加密文件系统,是通过mount/unmount操作作来开启关使能的。功能打开时,用户读写操作是知道不到数据加解密过程序的,即透明加密。
2、hello文件内容在mount前写入,在mount前都能正确访问(用例子只测了读操作,实际写也可以)。说明eCryptfs支持非持有加密文件和加密文件在一个目录内混合存储,并能正确访问(实际操作强烈不建议,见下一个用例)。
3、对于加密文件hello_encrypted,明文状态下长度为16 Bytes,加密状态下为12KB,变化比明示。
如果对上描述测试用例加载修改,调整mount -t ecryptfs参数,如修改passwd,取消no_sig_cache=y配置,打开文件名加密参数即ecryptfs_en able_filename_crypto=y,测试效果如下图:
从第2个修改后的用例可以观察到的现像/特性有:
4、ecryptfs支持文件名加密。由于文件名加密锁FNEK未在参数中指定,mount helper会提示/默认使用文件内含密锁(即图中) fnek_sig和fs_sig一致,需要说明的是加密密匙并非参数字中的passwd,后续结构和密码管理章节会说)。
5、虽然ecryptfs_passthrough特性仍然打开,即允许加密和非加密文件共存,但与上一个用例效果不同。启动文件名加密并挂载后,未加密文件hello无法在测试中显示,umount后又可正常访问。两个用例中passthrough特性在不同参数字下表现出不同,因此实际应用中,强烈不建议加密和非加密文件在一个目录混存。
另外补充一个现像/特性:
6、umount后,即加密的测试目录是可以直接传输/选择到其他主机/网络进行存储备份的。其他用户使用时,只需要使用相关同参数重新山即可正确访问。
关于用例中mount -t ecryptfs命令的相关参数汇总如下,详情可参考man ecryptfs手册及ecryptfs-utils源码。部分参数和意义会在架构分析和密匙中管理章节进行一步说明。
需要说明的是,上面描述的脚本实例的功能基础都可以使用ecryptfs-utils提供接口API实现。下面是作者实例的一个C实例的部分代码参考因为C程序需要引用ecryptfs.h头文件并使用相关API函数,需要安装libecryptfs-dev完整,并在编译时指定-lecryptfs链接对应库文件。
C用例中需要注意的是,mount操作前必须进行ecryptfs_add_passphrase_key_to_keyring,即会将passphrase转换成对应的key(实际为FEKEK,见后续分析),并注册到内核keyring,同时返回一个key_sig给用户后继续使用。
4.2、结果分析
从上节测试结果中,汇总的相关测试项以及eCryptfs效果特性如下表,需要说明的有两点:
一是对test目录重复挂载且每次使用不同密钥的效果。从下图例子看,对应passwd挂载后生成的文件,只能在该挂载上下文中正确访问。这这个例子简单说明,在参数情况变化下,例如文件名加密,情况可能更复杂和不确定,因此也不建议使用。
二是文件加密后大小变化问题,这个原因提出了eCryptfs的方案本身设计。下图是eCryptfs明文和密文的映射关系及论文中的说明,分别出自2006年设计文档《eCryptfs v0.1设计文档》和2007年论文《eCryptfs: a Stacked Cryptographic Filesystem》。初步可见加密格式文件会多增加一个标题信息(组建一个页面)。对于文件内容按页分块加密。为了综合性能力思考,故使文件大小做到页面对齐,最小12KB。
从方案设计和文件格式看,加密对于小文件来说丢失有点大,文件越大影响越小。下图分别用4M、40M、400M文件测试对比结果,知道源文件大小,加密后的文件大小增加8KB。
4.3、整体架构
eCryptfs整体架构如下图,主要是内核模块eCryptfs以及用户态进程ecryptfsd。ecryptfsd进程只在使用key类型为openssl模式时需要,使用passphrase模型(如上描述测试用例)时不需要。ecryptfs-utils可作为用户状态辅助工具或C接口编程参考。
应用程序发起系统调用时先经过VFS,判断目录类型为eCryptfs时调用eCryptfs模块的注册函数。之后eCryptfs根根据mount session中保存的密钥签名参数从keyring中找到对应用密匙(FEKEK),再调用crypto模块API完成文件加解密。
eCryptfs核心加解密机制如下图,主要结论如下:
1、FEK(文件加密密钥)唯一,即每个文件的加密密钥均不同,是随文件创建时生成的一个随机数。
2、每个文件的FEK经过FEKEK(File Encryption Key Encryption Key)加密保,加密后FEK称为EFEK(Encrypted File Encryption Key),并保存在eCryptfs加密文件的header信息中(如前所述) 0区)。
3、passphrase模式下,FEKEK是基于用户passphrase_passwd派生而来,派生方式是哈希计算(参考代码分析章节)。
4、文件内容按照页面大小(Data Extent)进行块加密。
核心过程可简单描述为:
1、新文件加密时,生成随机数FEK,对文件内容进行分块加密并存储。根据用户上传的key_sig参数从keyring找到对应的FEKEK ,用FEKEK加密FEK,生成EFEK并保存在文件header中。
2、解密时,同样根绝key_sig找到FEKEK,用FEKEK解密EFEK后得到FEK,再用FEK解密文件内容。
4.4、按键管理
从上节中我们了解到eCryptfs核心机制作中主要有两个KEY,即FEKEK和FEK,前者和用户输入passphrase_passwd有关,后者是每个文件唯一的随机数。下面结合ecryptfs-utils源码,分别介绍这两个关键的生成过程。
1、用用户passphrase_passwd 到FEKEK的转换
从C测试用例中看,opt参数只有key_sig信息,并不指定FEKEK。而mount操作前提示已添加对应key(FEKEK)到内核keyring。脚本命令实际上是挂载助手协助(隐式)完成了添加密钥环的操作。
核心函数即C示例中调用的ecryptfs_add_passphrase_key_to_key_ring,该函数的调用关系如下图:
首先ecryptfs_generate_passphrase_auth_tok会根据用户输入的passphrases信息、salt信息(参数指定,ecryptfs-utils有一个默认值ECRYPTFS_DEFAULT_SALT如下图),在generate_pass phrase_sig函数中进行哈希计算,将结果记录在变量fekek中,然后对fekek再进行一次hash计算,结果记录为passphrase_sig/auth_token_sig,并返回给用户后续使用(key_sig)。
generate_payload则为每次会话创建一个auth_tok结构体,记录更多加解密相关信息。
最后调用ecryptfs_add_auth_tok_to_keyring中,将对应的FEKEK、key_sig、salt等信息都添加到keyring中。至此就完成了从passphrase_passwd到FEKEK的转换和内核keyring添加。
2、FEK的生成过程
FEK 作为文件内容加密密钥,是每个文件唯一的随机数。生成时机是在 create 系统调用阶段,具体是在内核函数 ecryptfs_new_file_context 和 ecryptfs_generate_ new_key中完成,代码见下。
4.5、代码分析
本节将eCryptfs方案核心流程的代码调用关系进行了简单整理并罗列,供读者参考和对照阅读,不做详细划分析。
1、挂载过程关键函数调用。
从mount_crypt_stat key结构体,以及tokens结构体中可以看出,mount opt只接受key签名信息。
2、创建过程关键函数调用。
create过程中创建新文件,此时ecryptfs_crypt_stat结构体中保存了文件中每个的加密参数信息。
3、open过程关键函数调用。
4、读写过程关键函数调用。
五、总结
首先介绍了磁盘加密技术背景,包括威胁模型、技术路线和特点,以及根据加密对象差异,分别介绍推出了FDE和FBE两种磁盘加密方案,包括软硬件实现、文件系统实现差异等,并做出对比分析。最后重点介绍了Linux系统中典型的FBE方案及特点,并以eCryptfs为例进行了详细分析。
希望能帮助阅读者对磁盘加密技术概念、FDE和FBE区别、行业FBE方案特点、以及FBE实用关键技术能一步了解。限于篇幅,很多技术细节和方案无法再深入展开,如fscrypt。希望在后续文章中能结合Android FBE对fscrypt做进一步分享。
参考资料:
使用中的数据 https://en.wikipedia.org/wiki/Data_in_use
传输中的数据 https://en.wikipedia.org/wiki/Data_in_transit
静态数据 https://en.wikipedia.org/wiki/Data_at_rest
静态数据加密 https://wiki.archlinux.org/title/Data-at-rest_encryption
磁盘加密 https://en.wikipedia.org/wiki/Disk_encryption
全磁盘加密 https://en.wikipedia.org/wiki/Disk_encryption#Full_disk_encryption
预启动身份验证 https://en.wikipedia.org/wiki/Pre-boot_authentication
什么是全盘加密 https://specopssoft.com/blog/what-is-full-disk-encryption/
基于硬件的全盘加密 https://en.wikipedia.org/wiki/Hardware-based_full_disk_encryption
自加密驱动器 https://wiki.archlinux.org/title/Self-encrypting_drives
磁盘加密软件 https://en.wikipedia.org/wiki/Disk_encryption_software
磁盘加密软件比较 https://en.wikipedia.org/wiki/Comparison_of_disk_encryption_software
文件系统级加密 https://en.wikipedia.org/wiki/Filesystem-level_encryption
加密文件系统列表 https://en.wikipedia.org/wiki/List_of_cryptographic_file_systems
用户空间的文件系统,FUSE https://en.wikipedia.org/wiki/Filesystem_in_Userspace
基于 FUSE 的 FBE 对比 https://nuetzlich.net/gocryptfs/comparison/
fscrypt 内核文档 https://docs.kernel.org/filesystems/fscrypt.html
eCryptfs 文档 https://www.ecryptfs.org/documentation
eCryptfs Linux 手册页 https://linux.die.net/man/7/ecryptfs
2005.07 eCryptfs:Linux 的企业级加密文件系统 https://web.archive.org/web/20080916022422/http://www.linuxsymposium.org/2005/linuxsymposium_procv1.pdf
2006.03 eCryptfs v0.1 设计文档 http://www.dubeyko.com/development/FileSystems/eCryptfs/ecryptfs_design_doc_v0_1.pdf
2007.05 eCryptfs:堆叠式加密文件系统 http://www.dubeyko.com/development/FileSystems/eCryptfs/ecryptfs-article.pdf
2016.01动态加密技术综述,梁金千 http://blog.nsfocus.net/dynamic-encryption-technology-review/
2017.09 文件系统和块层加密:理论、实践和改进 https://www.snia.org/educational-library/file-system-and-block-layer-encryption-theory-practice-and-improvement- 2017年
上一篇 : 环球播报:元贝驾考科目一仿真考试_元贝清蒸要多久为好
下一篇 : 最后一页