Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to store key using Android Key Store Provider

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?

like image 815
Donal Rafferty Avatar asked Sep 25 '14 15:09

Donal Rafferty


2 Answers

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?

like image 99
Sid Avatar answered Sep 22 '22 11:09

Sid


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.

like image 44
Patrick Favre Avatar answered Sep 22 '22 11:09

Patrick Favre