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版本的安全密钥,并正确执行凭证创建流程(包括用户验证)。