使用FIDO2实现LUKS磁盘加密的技术解析

102 阅读3分钟

LUKS磁盘加密与FIDO2

FIDO2安全密钥提供多种用户认证方式。在ph0wn研讨会上我们探讨了部分应用场景,本文深入介绍如何使用安全密钥保护LUKS磁盘加密,并解析底层机制与常见陷阱。

LUKS磁盘加密基础

LUKS是Linux生态中加密块设备(如固态硬盘)的通用方案。其工作原理是在加密设备前保留未加密的头部,包含解密所需的所有信息。头部包含用于解密二进制密钥槽区域的密钥派生信息,而密钥槽中的主密钥则用于加解密整个设备。

管理加密设备的常用工具是cryptsetup。例如使用luksFormat子命令创建LUKS设备:

$ cryptsetup luksFormat disk.img

该命令会请求用于设备加解密的密码,随后完成磁盘格式化与加密。可通过open命令解锁设备:

$ sudo cryptsetup open disk.img encrypted

FIDO2 hmac-secret扩展加密

FIDO2采用标准化通信协议CTAP(客户端到认证器协议),定义安全密钥与操作系统/浏览器的信息交换。当前版本为2.1,2.2版已发布评审草案。

对于LUKS加密,使用名为"hmac-secret"的CTAP扩展。该扩展通过authenticatorMakeCredential和authenticatorGetAssertion命令获取LUKS密钥槽解密的对称密钥。可通过Yubico python-fido2库的get_info.py脚本验证认证器是否支持此扩展:

$ python get_info.py

输出显示设备支持CTAP 2.0标准及hmac-secret扩展。

在CTAP authenticatorMakeCredential命令中,若存在hmac-secret参数,认证器会创建凭证ID并生成32字节随机数CredRandom。systemd提供的systemd-cryptenroll工具可便捷地注册认证器:

$ systemd-cryptenroll --fido2-device=auto --wipe-slot=all test.img

注册后查看LUKS头部可见关联密钥槽的令牌,其中包含fido2-credential(凭证ID)和fido2-salt(盐值)。

密钥生成使用CTAP authenticatorGetAssertion命令。通过Diffie-Hellman密钥协商获得共享密钥,用于加密和验证主机选择的盐值。认证器生成CredRandom与盐值的HMAC-SHA-256输出:

output = HMAC-SHA-256(CredRandom, salt)

该加密输出返回主机后用于解密关联密钥槽。解密时需要认证器和PIN码:

$ sudo cryptsetup open --token-only image.img encrypted

由于CredRandom仅能由安全密钥恢复,缺少认证器无法解密设备。

PIN码管理问题

CTAP在凭证创建时使用clientPin参数。若未设置PIN码即注册安全密钥,后续即使配置PIN码也不会要求输入,这可能导致设备与认证器同时被盗时数据泄露。

实验发现,某些认证器(如固件v3.0.0的Solo key)在修改LUKS头部fido2-clientPin-required为false后,仍可不需PIN码解密设备。但Yubikey 5.1.1等设备则拒绝此类请求。

CTAP协议更新

CTAP 2.1及以上版本修复了该缺陷。认证器在authenticatorMakeCredential命令中生成两个独立密钥:CredRandomWithUV和CredRandomWithoutUV。根据用户验证状态选择相应密钥。

测试支持CTAP 2.1的YubiKey 5 NFC时发现,修改头部参数后解密尝试因密钥验证失败而拒绝访问,这与使用不同CredRandom值导致密钥生成差异的原理一致。

该更新已实现在最新Solo key固件中,但部分认证器可能无法升级,因此设置磁盘加密前需确认设备支持的CTAP版本。

结论

FIDO2安全密钥为LUKS加密磁盘提供了便捷安全的解锁方案,但必须理解底层机制和潜在风险。为确保最佳保护,应使用支持最新CTAP版本的安全密钥,并正确执行凭证创建流程(包括用户验证)。