7、指纹数据安全存储:加密存储方案、TEE安全存储、文件系统加密、密钥派生机制

指纹数据一旦被提取出来,接下来的问题就是:放哪儿才安全?

说实话,这是整个指纹认证里最敏感的一环。你想想看,指纹特征数据一旦泄露,用户是没法像改密码那样「换一根手指」的。所以Android系统在这块下了狠功夫,从硬件隔离到加密存储,层层设防。

7.1 核心原则:指纹数据绝不能落盘明文

我在项目里见过一些厂商为了赶工期,把指纹特征直接写进/data分区的一个文件里。嗯,这种操作在出厂测试阶段可能没问题,但一旦量产,就是灾难级的漏洞。

Android官方的要求很明确:指纹特征数据必须加密存储,且密钥不能暴露给普通世界(Normal World)。说白了,就算攻击者拿到了整个文件系统,他也只能看到一堆乱码。

安全存储的三大防线:

  • 第一道:TEE安全存储 —— 硬件隔离,密钥不出安全世界
  • 第二道:文件系统加密(FBE/FDE) —— 内核级加密,防止冷启动攻击
  • 第三道:密钥派生机制 —— 每次加密用不同的密钥,降低泄露影响

7.2 TEE安全存储:真正的「保险柜」

TEE(Trusted Execution Environment)是什么?你可以把它理解成手机主芯片里的一个独立安全小世界。这个小世界有自己的CPU、内存和存储,和Android主系统(REE)完全隔离。

指纹传感器采集到原始图像后,特征提取和比对都在TEE里完成。特征数据最终存在TEE的加密文件系统中,REE侧根本读不到。

我个人的习惯:在调试TEE存储时,一定要确认REE侧是否真的无法访问。我曾经遇到过某款芯片的TEE驱动有个debug接口,REE侧可以通过ioctl直接读取TEE内存——这相当于保险柜门没锁。

TEE存储的典型流程是这样的:

  1. 指纹传感器在TEE上下文中采集图像
  2. TEE内的算法库提取特征点
  3. 特征数据通过TEE内部加密引擎加密
  4. 密文写入TEE专属的RPMB分区(Replay Protected Memory Block)
  5. REE侧只能通过Gatekeeper接口查询「是否匹配」,拿不到原始数据

7.3 文件系统加密:FBE与FDE的区别

很多人会把TEE存储和文件系统加密搞混。其实它们是不同层面的保护:

  • FDE(全盘加密): 整个/data分区用一个密钥加密,开机时输入密码解锁。缺点是解锁后所有数据都可见。
  • FBE(基于文件的加密): 每个文件或每个目录用不同的密钥。指纹数据通常放在一个独立的加密目录下,只有指纹服务进程能访问。

我个人更推荐FBE方案。为什么?因为FDE在手机解锁后,所有应用的数据都是明文状态。而FBE可以做到:即使手机已解锁,指纹目录的密钥仍然只在TEE里,REE侧的应用根本打不开。

特性 FDE FBE
加密粒度 整个分区 每个文件/目录
解锁后安全性 所有数据可见 可单独保护敏感目录
密钥存储 存储在加密芯片 存储在TEE或Keymaster
指纹数据适用性 不推荐 推荐

7.4 密钥派生机制:一钥一用

这里有个关键问题:指纹数据加密的密钥从哪来?

直接写死在代码里?那肯定不行。用用户密码派生?那换密码时所有指纹数据都得重新加密。

Android的做法是:使用密钥派生函数(KDF),从硬件绑定的根密钥(HUK,Hardware Unique Key)派生出多个子密钥。

典型的派生流程:

// 伪代码示意
HUK = 从eFuse读取的芯片唯一密钥
fingerprint_key = HKDF(HUK, salt="fingerprint_v1", info="template_encrypt")
template_encrypted = AES-256-GCM(template_data, fingerprint_key)

为什么要用HKDF而不是直接哈希?因为HKDF可以加入「上下文信息」(info参数),这样每个用途的密钥都不一样。指纹加密密钥、锁屏密码密钥、应用数据密钥,三者互不相关。

我曾经踩过的坑:某个项目里,工程师把HUK直接当AES密钥用。结果发现,如果HUK在产线写入时出了偏差,所有手机都无法解密指纹数据。正确的做法是用HUK作为根密钥,通过KDF派生出工作密钥。这样即使工作密钥泄露,HUK仍然是安全的。

7.5 整体架构图

下面这张图展示了指纹数据从采集到存储的完整路径:

指纹数据安全存储架构 REE(普通世界) TEE(安全世界) 指纹应用 请求认证 FingerprintService 系统服务 FBE加密目录 加密存储 指纹TA 可信应用 特征提取 算法模块 TEE安全存储 RPMB分区 密钥派生 HKDF 认证请求 加密特征数据 数据流 密钥流

7.6 避坑指南:常见的安全隐患

做了这么多年指纹方案,我总结了几条最容易出问题的地方:

  • 密钥硬编码: 有些厂商为了调试方便,把加密密钥写死在代码里。这是最愚蠢的错误,没有之一。
  • TEE与REE共享内存: 如果TEE和REE通过共享内存传递指纹数据,攻击者可能通过DMA直接读取。一定要用安全内存(Secure Buffer)。
  • 日志泄露: 我曾经在logcat里看到过厂商打印的指纹特征hex dump。嗯,这种日志一旦发布到用户手机上,等于公开了用户的指纹数据。
  • 密钥更新策略: 当用户删除指纹时,对应的加密密钥必须立即销毁。有些系统只是删除了密文,密钥还留在TEE里——这给了攻击者重放攻击的机会。

一个小建议:在开发阶段,可以用测试密钥。但量产前一定要换成从eFuse读取的HUK。我见过一个团队,测试密钥忘了换,结果所有量产手机的指纹加密密钥都是同一个值——这跟没加密一样。

指纹数据的安全存储,说白了就是一场「攻防博弈」。攻击者会想尽办法从REE侧读取TEE内存、从文件系统里扒数据、从日志里找线索。而我们能做的,就是利用硬件隔离、加密存储和密钥派生这三板斧,把攻击者的路全部堵死。

记住一句话:指纹数据的安全,不在于加密算法有多强,而在于密钥管理有多严


公众号:蓝海资料掘金营,微信deep3321