问题
I need to tell if my keys created are in the hardware backed AndroidKeyStore(TEE or SE) or the software backed implementation.
I understand that for api < 23 I should be using KeyChain.isBoundKeyAlgorithm(algorithm)
and for api >= 23 I should use keyInfo.isInsideSecureHardware
.
However, I have a Nexus 6, Android 7.1.1 api level 25. I created a keypair in AndroidKeyStore and when I call keyInfo.isInsideSecureHardware
, it returns false
but when i try calling KeyChain.isBoundKeyAlgorithm(algorithm)
, it returns true
.
So my question is, is the keypair inside the hardware backed keystore(TEE/SE) or not?
Here is my function to check if the key is inside hardware back keystore or not
fun checkKeyInHardware(): Boolean {
val key = androidKeyStore.getKey(AUTH_ALIAS, null) as PrivateKey
val algorithm = key.algorithm
Log.d("checkKeyInHardware", "Key algo = $algorithm")
Log.d("checkKeyInHardware", "KeyChain.isBoundKeyAlgorithm(algorithm) = ${KeyChain.isBoundKeyAlgorithm(algorithm)}")
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", "not in AndroidKeyStore")
null
}
return if(keyInfo == null) {
Log.d("checkKeyInHardware", "keyinfo is null")
false
}
else {
Log.d("checkKeyInHardware", "keyInfo.isInsideSecureHardware = ${keyInfo.isInsideSecureHardware}")
keyInfo.isInsideSecureHardware || KeyChain.isBoundKeyAlgorithm(algorithm)
}
} else {
KeyChain.isBoundKeyAlgorithm(algorithm)
}
}
and here is how i generate my key pairs
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
val originationEnd = Date(start.time + ORIGINATION_TIME_OFFSET)
val consumptionEnd = Date(end.time + CONSUMPTION_TIME_OFFSET)
val kpg = KeyPairGenerator.getInstance(KeyProperties.KEY_ALGORITHM_EC, androidKeyStoreProvider)
val paramSpecBuilder: KeyGenParameterSpec.Builder = KeyGenParameterSpec
.Builder(AUTH_ALIAS, KeyProperties.PURPOSE_SIGN)
paramSpecBuilder.apply {
setDigests(KeyProperties.DIGEST_SHA256, KeyProperties.DIGEST_SHA384, KeyProperties.DIGEST_SHA512)
setAlgorithmParameterSpec(ecGenParameterSpec)
setCertificateNotBefore(start)
setCertificateNotAfter(end)
setKeyValidityStart(start)
setKeyValidityEnd(end)
setKeyValidityForOriginationEnd(originationEnd)
setKeyValidityForConsumptionEnd(consumptionEnd)
setCertificateSubject(subjectPrincipal)
setUserAuthenticationRequired(false)
setCertificateSerialNumber(serialNumber)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
setAttestationChallenge(challenge)
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
val paramSpec = paramSpecBuilder.setIsStrongBoxBacked(true).build()
kpg.initialize(paramSpec)
try {
generateKeyCatcher { kpg.generateKeyPair() }
} catch (e: StrongBoxUnavailableException) {
val weakBoxParamSpec = paramSpecBuilder.setIsStrongBoxBacked(false).build()
kpg.initialize(weakBoxParamSpec)
generateKeyCatcher { kpg.generateKeyPair() }
}
} else {
val paramSpec = paramSpecBuilder.build()
Log.d("GenerateKey", "PROVIDER = ${kpg.provider.name}")
kpg.initialize(paramSpec)
generateKeyCatcher { kpg.generateKeyPair() }
}
}
else {
rearrangeSecurityProviders()
val kpg = KeyPairGenerator.getInstance("RSA", androidKeyStoreProvider)
val spec = KeyPairGeneratorSpec.Builder(context).run {
setAlias(AUTH_ALIAS)
setSubject(subjectPrincipal)
setSerialNumber(BigInteger.ONE)
setKeyType("EC")
setKeySize(256)
setAlgorithmParameterSpec(ecGenParameterSpec)
setStartDate(start)
setEndDate(end)
build()
}
Log.d("GenerateKey", "PROVIDER = ${kpg.provider.name}")
Log.d("GenerateKey", "PROVIDER = ${kpg.provider}")
kpg.initialize(spec)
generateKeyCatcher { kpg.generateKeyPair() }
}
回答1:
Your key is not hardware backed.
KeyInfo.isInsideSecureHardware()
provides reliable information about the key in question, whereas KeyChain.isBoundKeyAlgorithm()
will tell if the back-end, i.e., Keymaster the TEE or SE trusted app, supports the given algorithm.
There can be a few reasons why you see this discrepancy. Keymaster versions < 1.0 implemented some parameter combinations but not others. There were also buggy KM 1.0 implementations that occasionally failed to generate EC keys. In both cases a software fallback would take over and generate the key in software.
KeyChain.isBoundKeyAlgorithm()
is too coarse a check to tell if every combination is supported, and it won't tell if the back-end is buggy. So despite it returning true
, your key ends up being software backed.
Starting with KM2.0 this fallback as been deactivated. So devices with KM2.0 or newer will generate the key in hardware (TEE/SE) or not at all.
For reliable information about asymmetric keys and conveying this information to a remote relying party, consider using Keystore Key Attestation. However, this feature is hardware enforced only since KM2.0 and newer.
来源:https://stackoverflow.com/questions/57554971/how-to-tell-if-keys-are-hardware-backed