背景
Android平台上,GateKeeper+KeyMint是一种常见的密码解锁方案,基于仅用户知道的密码保护用户的数据。Weaver是一种基于Secure Element等防篡改硬件,旨在增强密码保护用户数据的解决方案,提供了device-off security threat model和brute force password guessing两个关键特性。
device-off security threat model:当设备关闭电源时,用户身份验证和磁盘加密依赖的secret存储在安全芯片中,必须使用用户LSKF (pin/pattern/password)才能获取到该值。
brute force password guessing:通过安全芯片内部的安全计时器防止攻击者通过暴力破解的手段推演出用户密码。
Weaver 整体架构
录入密码
校验密码
密码解锁关键接口
doVerifyCredential in LockSettingsService.java
SystemUI 监听用户输入密码,基于Password/PIN/Pattern 生成 credential 传递给 LockSettings 校验并监听校验结果。 authResult = mSpManager.unlockLskfBasedProtector( getGateKeeperService(), protectorId, credential, userId, progressCallback); | |
LockSettings 基于 gatekeeper 或 weaver 根据 UI 传入的 credential 解密出解锁的关键数据 synthetic password。 response = mSpManager.verifyChallenge(getGateKeeperService(), authResult.syntheticPassword, 0L /* challenge */, userId); | |
上一步成功解密出 synthetic password 后,会调用 gatekeeper 进行认证。认证成功后,调用解锁成功后的各种接口。 onCredentialVerified(authResult.syntheticPassword, PasswordMetrics.computeForCredential(credential), userId); |
GateKeeper+KeyMint 传统方案
unlockLskfBasedProtector in SyntheticPasswordManager.java
LockSettings 从 (sp-handle).pwd 中解析出 pwd,stretchLskf 方法基于 SystemUI传入的 credential 和之前解析出的 pwd 通过 scrypt 方法计算出 stretchedLskf。 byte[] stretchedLskf = stretchLskf(credential, pwd); | |
LockSettings 基于上面计算出来的 stretchedLskf 计算出 gkPassword,本质上是个 SHA-512 摘要算法。 byte[] gkPassword = stretchedLskfToGkPassword(stretchedLskf); | |
GateKeeper 基于 fakeUserId 和 刚刚计算出来的 gkPassword 进行一次认证(此时还没有解密出 synthetic password,因此无法对真正的 UserId 进行认证)。 response = gatekeeper.verifyChallenge(fakeUserId(userId), 0L, pwd.passwordHandle, gkPassword); | |
fakeUserId 认证成功之后,LockSettings 结合 stretchedLskf 从 (sp-handle).secdis 中解密出 protectorSecret 。 protectorSecret = transformUnderSecdiscardable(stretchedLskf, secdiscardable); |
Weaver+GateKeeper+KeyMint 增强方案
unlockLskfBasedProtector in SyntheticPasswordManager.java
SystemUI 监听用户输入密码,基于 Password/PIN/Pattern 生成 credential 传递给 LockSettings 校验并监听校验结果。 byte[] stretchedLskf = stretchLskf(credential, pwd); | |
Locksettings将UI传入的credential下发给weaver,进一步解密出解锁的关键数据synthetic password。 result.gkResponse = weaverVerify(weaverSlot, stretchedLskfToWeaverKey(stretchedLskf)); | |
上一步成功解密出 synthetic password 后,会调用 gatekeeper 进行认证。认证成功后,调用解锁成功后的各种接口。 protectorSecret = transformUnderWeaverSecret(stretchedLskf, result.gkResponse.getGatekeeperHAT()); |
Weaver 密码解锁方案的优势
传统方案的暴破思路
关机暴力破解思路
1. 攻击者截获splob第一次解密后的中间密文Intermediate;
2. 第二次解密使用AES-GCM模式,错误的密钥无法解密成功;
3. 攻击者在外部高性能环境中不停的通过临时生成的密码;
4. 并使用运算出的SecretKey对之前截获的中间密文进行解密;
5. 解密成功则证明当次生成的密码是正确的。
在VM/PC运行以下伪代码:
while(1) {
pwd = generateRandomPassword();
token = scrypt(pwd, R, N, P, Salt);
secretKey = getSecretKey(token);
if (SUCCESS == aesDecrypt(Intermediate, secretKey))
return pwd;
}
}
Weaver 方案防暴破思路
防暴力破解思路
1. 传统方案可以脱离设备在外部环境计算secretKey,绕过设备自身的节流机制;
2. Weaver方案计算SecretKey必须向SE传入正确的key值,并从中获取到正确的secret值;
3. SE内部的硬件定时器具备节流机制,即多次传入错误的key,等待重试的时间会指数级上升。
Weaver 密码解锁方案的局限
Weaver HAL必须通过OMAPI与安全芯片通信。OMAPI服务openLogicalChannel被调用时,会先检查调用者的Access Control Rules是否存在后,才会创建和安全芯片通信的channel,这个操作会消耗大量时间。
优化思路
针对Weaver特性进行Channel绑定,即启动过程中访问Weaver Applet时,打开一个固定的逻辑通道不关闭,从而规避每次打开逻辑通道的时间开销,但需要安全芯片供应商做好功耗控制。
总结
传统密码解锁方案的节流机制在Gatekeeper TA中实现,这为暴力破解锁屏密码提供了可能。Weaver方案的节流在安全硬件中实现,攻击者很难从安全芯片中读取中间秘密值或是绕过其节流机制。
往
期
推
荐
Android 系统服务DisplayManagerService和DisplayDevice生命周期解读
探索Android动态埋点的新视界:UprobeStats深度解析