Regarding Android Keystore system article,
Key material never enters the application process. When an application performs cryptographic operations using an Android Keystore key, behind the scenes plaintext, ciphertext, and messages to be signed or verified are fed to a system process which carries out the cryptographic operations. If the app's process is compromised, the attacker may be able to use the app's keys but cannot extract their key material (for example, to be used outside of the Android device)
So, my question is why is in BasicAndroidKeyStore, developer able to get the KeyPair object and then print its public/private keys?
If developer can access the keys, how this system can be considered to be secured? It's not. If an attacker compromises the app process, he can easily retrieve the kays and use outside of the device.
The Android Keystore system lets you store cryptographic keys in a container to make it more difficult to extract from the device. Once keys are in the keystore, they can be used for cryptographic operations with the key material remaining non-exportable.
The Android Keystore system lets you store cryptographic keys in a container to make them more difficult to extract from the device. Once keys are in the keystore, you can use them for cryptographic operations, with the key material remaining non-exportable.
First call keytool -list -keystore myStore to know which alias to look for, then call this program with the passwords and parameters. In case of a private key entry, it shows the key itself and additionally a self-signed certificate which contains the public key, in a readable form.
The example code that you pointed to from BasicAndroidKeyStore does not log the public key as getPublic() from the KeyPair class only returns a reference the the public key object, not the public key itself.
Log.d(TAG, "Public Key reference is: " + kp.getPublic().toString());
Logs:
D/KeyStoreFragment: Public Key reference is: android.security.keystore.AndroidKeyStoreRSAPublicKey@b8004e8f
The same goes for getPrivate().
Log.d(TAG, "Private Key reference is: " + kp.getPrivate().toString());
Logs:
D/KeyStoreFragment: Private Key reference is android.security.keystore.AndroidKeyStoreRSAPrivateKey@5da42c27
Now, as you point out in your comment, kp.getPublic().getEncoded()
will return the actual public key, but a public key's original purpose is not meant to be secret.
The private key is meant to be secret and while using a hardware-backed keystore with keys supported in the device's secure hardware, the secret keys are stored safely in the TEE/SE and cannot be extracted by the app itself or another bad actor with root privileges. You can see it in this example:
Log.d(TAG, "Private Key is " + Arrays.toString(kp.getPrivate().getEncoded()));
Logs:
D/KeyStoreFragment: Private Key is null
To verify your keys are supported by your device's secure hardware, you can use some variation of this code to suit your needs. You can paste this snippet after the same Log.d mentioned above in the example app's createKeys() method.
KeyFactory factory = KeyFactory.getInstance(kp.getPrivate().getAlgorithm(), "AndroidKeyStore");
KeyInfo keyInfo = null;
try {
keyInfo = factory.getKeySpec(kp.getPrivate(), KeyInfo.class);
} catch (InvalidKeySpecException e) {
e.printStackTrace();
}
if (keyInfo.isInsideSecureHardware())
Log.d(TAG, "Key is supported in secure hardware");
else
Log.d(TAG, "Key is not supported in secure hardware");
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