I am trying to use the Android Key Store Provider that became available in Android 4.3 to securely save a Private Key and to then use this private key to encrypt and decode data.
I think I have implemented the correct approach and code for this so far however I am currently facing an odd issue that I cannot figure out.
I have a class called KeyStorage that I use to create the Key pair, load the KeyStore and retrieve the private key, the code for this class is as follows:
public class KeyStorage {
public static final String ANDROID_KEYSTORE = "AndroidKeyStore";
private KeyStore keyStore;
public void loadKeyStore() {
try {
keyStore = KeyStore.getInstance(ANDROID_KEYSTORE);
keyStore.load(null);
Enumeration<String> aliases = keyStore.aliases();
while(aliases.hasMoreElements())
Log.e("E", "Aliases = " + aliases.nextElement());
} catch (Exception e) {
// TODO: Handle this appropriately in your app
e.printStackTrace();
}
}
public void generateNewKeyPair(String alias, Context context)
throws Exception {
Calendar start = Calendar.getInstance();
Calendar end = Calendar.getInstance();
// expires 1 year from today
end.add(1, Calendar.YEAR);
KeyPairGeneratorSpec spec = new KeyPairGeneratorSpec.Builder(context)
.setAlias(alias)
.setSubject(new X500Principal("CN=" + alias))
.setSerialNumber(BigInteger.TEN)
.setStartDate(start.getTime())
.setEndDate(end.getTime())
.build();
// use the Android keystore
KeyPairGenerator gen = KeyPairGenerator.getInstance("RSA", ANDROID_KEYSTORE);
gen.initialize(spec);
// generates the keypair
gen.generateKeyPair();
}
public PrivateKey loadPrivteKey(String alias) throws Exception {
if (keyStore.isKeyEntry(alias)) {
Log.e("E", "Could not find key alias: " + alias);
return null;
}
KeyStore.Entry entry = keyStore.getEntry(EnhancedCredentialStore.KEY_ALIAS, null);
if (!(entry instanceof KeyStore.PrivateKeyEntry)) {
Log.e("E", " alias: " + alias + " is not a PrivateKey");
return null;
}
return ((KeyStore.PrivateKeyEntry) entry).getPrivateKey();
}
I then have a class called CredentialStore that I try to use this in. I create an alias called "MySecureKey" and try to create and store a private key based on this. So as you can see I try to create the new Key pair based on the Alias load the keystore and then finally retrieve the Private key. However it doesn't work.
public class CredentialStore {
public static final String KEY_ALIAS = "MySecureKey";
private KeyStorage KeyStorage;
public CredentialStore(Activity context){
keyStorage = new KeyStorage();
try {
keyStorage.generateNewKeyPair(KEY_ALIAS, context);
} catch (Exception e) {
e.printStackTrace();
}
blueBirdKeyStorage.loadKeyStore();
try {
keyStorage.loadPrivteKey(KEY_ALIAS);
} catch (Exception e) {
e.printStackTrace();
}
}
I get the logs as follow:
Aliases = MySecureKey
Could not find key alias: MySecureKey
So when I check the aliases in the loadKeyStore method it looks like it is there as it is coming back in the log. However when I try to call it using the loadKeyStore method I get the log saying it can not find the key "MySecureKey".
I cannot find any reason for this and researching online has proven unfruitful so I was wondering if anyone has any idea what might be going wrong?
Why is it blueBirdKeyStore in:
blueBirdKeyStorage.loadKeyStore();
Shouldn't it be:
keyStorage.loadKeyStore();
Also, you haven't used the 'alias' in your loadPrivateKey():
KeyStore.Entry entry = keyStore.getEntry(EnhancedCredentialStore.KEY_ALIAS, null);
Now, I'm not sure, but shouldn't you be using the 'alias' in this?
Your method to check if your key exists is flawed:
if (keyStore.isKeyEntry(alias)) {
Log.e("E", "Could not find key alias: " + alias);
return null;
}
According to the javadoc .isKeyEntry()
has the following behavior
Returns true if the entry identified by the given alias was created by a call to setKeyEntry, or created by a call to setEntry with a PrivateKeyEntry or a SecretKeyEntry.
but your key was not created through setEntry()
. I guess if you just load the key with
KeyStore.Entry entry = ks.getEntry(alias, null);
it won't be null.
Here is a full example with simple methods on how to use the Android Keystore with pre-M and M Apis.
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