Android 6.0+ has a KeyInfo
class to get info on a key saved in the AndroidKeyStore
. On the KeyInfo
class, we have isInsideSecureHardware()
and isUserAuthenticationRequirementEnforcedBySecureHardware()
methods. We also have isUserAuthenticationRequired()
. The documentation, as usual, sucks.
Based on method names and the (limited) documentation, it would seem as though isUserAuthenticationRequirementEnforcedBySecureHardware()
is simply a logical AND of
isInsideSecureHardware()
and isUserAuthenticationRequired()
.
Is there something more to it than that? If so, what does it mean for the user authentication requirement to be enforced by secure hardware, beyond just the key being in secure hardware?
The Android Keystore API and the underlying Keymaster HAL provide a basic but adequate set of cryptographic primitives to allow the implementation of protocols using access-controlled, hardware-backed keys.
StrongBox is an implementation of the Keymaster HAL that resides in a hardware security module. It is an important security enhancement for Android devices and paved the way for us to consider features that were previously not possible.
Most of the latest devices now have a secure hardware storage which stores encryption keys which can be used by apps, Providing more security by making the keys unavailable for extraction. That is, once keys are in a hardware-backed even the OS kernel cannot access this key.
The method isUserAuthenticationRequirementEnforcedBySecureHardware()
is not a logical AND of isInsideSecureHardware()
and isUserAuthenticationRequired()
.
But if you dig into the code, you can see that it is a logical AND of 3 things:
Snippet of code:
boolean userAuthenticationRequirementEnforcedBySecureHardware = (userAuthenticationRequired)
&& (keymasterHwEnforcedUserAuthenticators != 0)
&& (keymasterSwEnforcedUserAuthenticators == 0);
The difference is not whether the key is secure in hardware, but if user authentication is backed by hardware, not software. For most, if not all devices with fingerprint readers, user authentication in secure hardware means the TEE would contain two things that interact with the Keymaster Trusted App:
Example scenarios:
isUserAuthenticationRequirementEnforcedBySecureHardware()
could return false if both isInsideSecureHardware()
and isUserAuthenticationRequired()
return true, but the user authentication is done in SW and not in the TEE. (not likely)isUserAuthenticationRequirementEnforcedBySecureHardware()
could return true if isInsideSecureHardware()
returns false (key is not supported in device's secure hardware) and isUserAuthenticationRequired()
returns true with the user authentication done in HW. (possible)isUserAuthenticationRequirementEnforcedBySecureHardware() is simply a logical AND of isInsideSecureHardware() and isUserAuthenticationRequired().
I think that's not true (see methods below) it comes via the key
from KeyChain
.
Is there something more to it than that?
KeyInfo.java
is a container class for key
info from a KeyChain
.
Whether the key
is bound to the secure hardware is known only once the key
has been imported.
To find out, use:
{
PrivateKey key = ...; // private key from KeyChain
KeyFactory keyFactory =
KeyFactory.getInstance(key.getAlgorithm(), "AndroidKeyStore");
KeyInfo keyInfo = keyFactory.getKeySpec(key, KeyInfo.class);
if (keyInfo.isInsideSecureHardware())
{
// The key is bound to the secure hardware of this Android
}
}
From KeyInfo.java:
/**
* Returns {@code true} if the key resides inside secure hardware (e.g., Trusted Execution
* Environment (TEE) or Secure Element (SE)). Key material of such keys is available in
* plaintext only inside the secure hardware and is not exposed outside of it.
*/
public boolean isInsideSecureHardware()
{
return mInsideSecureHardware;
}
/**
* Returns {@code true} if the requirement that this key can only be used if the user has been
* authenticated is enforced by secure hardware (e.g., Trusted Execution Environment (TEE) or
* Secure Element (SE)).
*
* @see #isUserAuthenticationRequired()
*/
public boolean isUserAuthenticationRequirementEnforcedBySecureHardware()
{
return mUserAuthenticationRequirementEnforcedBySecureHardware;
}
/**
* Returns {@code true} if the key is authorized to be used only if the user has been
* authenticated.
*
* <p>This authorization applies only to secret key and private key operations. Public key
* operations are not restricted.
*
* @see #getUserAuthenticationValidityDurationSeconds()
* @see KeyGenParameterSpec.Builder#setUserAuthenticationRequired(boolean)
* @see KeyProtection.Builder#setUserAuthenticationRequired(boolean)
*/
public boolean isUserAuthenticationRequired()
{
return mUserAuthenticationRequired;
}
See also: KeyStore.java
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With