如何判断AndroidKeyStore生成的密钥是否为硬件加密(TEE/SE)?
Nexus 6(Android7.1.1)密钥硬件存储判定问题解答
核心结论先给你吃定心丸
你的EC密钥**确实是存储在硬件加密环境(TEE)**里的!出现keyInfo.isInsideSecureHardware=false但KeyChain.isBoundKeyAlgorithm=true的情况,是Nexus 6这个特定设备+Android7.x版本的系统实现特性导致的,并非你的代码问题。
为什么两个API返回结果矛盾?
咱们得先搞清楚这两个API的底层逻辑差异:
KeyInfo.isInsideSecureHardware(API23+):官方文档说它用来判断密钥是否在安全硬件(SE/TEE)中,但在Nexus 6的Android7.x系统里,这个API的实现比较局限——它只把**Secure Element(SE)算作“安全硬件”,而Nexus 6的EC密钥实际是存在Trusted Execution Environment(TEE)**中的,所以会返回false。KeyChain.isBoundKeyAlgorithm(algorithm):这个旧API的设计是判断密钥是否绑定到设备硬件(不管是TEE还是SE),在Nexus 6的7.1.1系统中,它能正确识别TEE中的密钥,所以返回true。
你的检查函数优化建议
你当前的函数逻辑已经做了很好的兼容,尤其是最后用keyInfo.isInsideSecureHardware || KeyChain.isBoundKeyAlgorithm(algorithm)的逻辑,刚好能覆盖Nexus 6这类系统实现有差异的设备。这里可以给你做一点小优化,让代码更健壮:
优化后的检查函数
fun checkKeyInHardware(): Boolean { val key = androidKeyStore.getKey(AUTH_ALIAS, null) as? PrivateKey ?: run { Log.d("checkKeyInHardware", "Failed to get private key") return false } val algorithm = key.algorithm Log.d("checkKeyInHardware", "Key algo = $algorithm") val isBoundToHardware = KeyChain.isBoundKeyAlgorithm(algorithm) Log.d("checkKeyInHardware", "KeyChain.isBoundKeyAlgorithm = $isBoundToHardware") return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { val factory = KeyFactory.getInstance(algorithm, androidKeyStoreProvider) val keyInfo = try { factory.getKeySpec(key, KeyInfo::class.java) } catch (e: InvalidKeySpecException) { Log.d("checkKeyInHardware", "Key not stored in AndroidKeyStore") null } ?: run { Log.d("checkKeyInHardware", "KeyInfo is null") return false } val isInSecureHardware = keyInfo.isInsideSecureHardware Log.d("checkKeyInHardware", "keyInfo.isInsideSecureHardware = $isInSecureHardware") // 兼容Nexus 6这类TEE未被isInsideSecureHardware识别的设备 isInSecureHardware || isBoundToHardware } else { isBoundToHardware } }
关于你的密钥生成代码
你的生成逻辑完全没问题:
- API25时不会触发StrongBox相关代码(StrongBox是API28才引入的特性),所以密钥会正常生成在Nexus 6的TEE中。
- Nexus 6的TEE完全支持EC密钥的存储和加密操作,所以你的密钥安全性是有保障的。
内容的提问来源于stack exchange,提问作者kyo171




