How to store key using Android Key Store Provider

12,325

Solution 1

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?

Solution 2

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.

Share:
12,325
Donal Rafferty
Author by

Donal Rafferty

Software Engineer

Updated on June 29, 2022

Comments

  • Donal Rafferty
    Donal Rafferty almost 2 years

    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?

    • Alexander Zhak
      Alexander Zhak over 9 years
      1. You generate KeyPair and don't make use of it. Your generateNewKeyPair method doesn't return anything. 2. You don't save anything to KeyStore to load it later. please refer to a sample on KeyStore useage. It might help you developer.android.com/samples/BasicAndroidKeyStore/index.htm‌​l
    • Patrick
      Patrick over 7 years
      @AlexanderZhak altough the many upvotes, your comment is wrong: check out the official doc: developer.android.com/training/articles/… this is how you use the Android Keystore - it is not necessary to put the key explicitly if you use the KeyFactory with the Android Keystore instance.