1

I use Android application to generate KeyPair, create CSR and send it to my CA. During keyPair generation i use "AndroidKeyStore":

 KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA","AndroidKeyStore");
        keyPairGenerator.initialize(new KeyGenParameterSpec.Builder(
                alias,
                KeyProperties.PURPOSE_SIGN | KeyProperties.PURPOSE_VERIFY)
                .setKeySize(KEY_PAIR_LENGTH)
                .setDigests(KeyProperties.DIGEST_SHA256)
                .setSignaturePaddings(KeyProperties.SIGNATURE_PADDING_RSA_PSS)
                .build());
        return keyPairGenerator.generateKeyPair();

so PrivateKey is generated and stored inside KeyStore.

When I get X509Certificate (signed CSR) from my CA i would like to install PrivateKey and Certificate using KeyChain API:

PKCS12 = ?!
Intent intent = createInstallIntent();
intent.putExtra(KeyChain.EXTRA_PKCS12, PKCS12);

Is it possible to use AndroidKeyStore in that situation? I read it is impossible to get PrivateKey from AndroidKeyStore.

macieg_b
  • 165
  • 3
  • 15
  • Key material can not be extracted from Android Keystore. If you need a Pkcs12 to install the certificate in the Android Keychain then you would need to use a private keystore from your app – pedrofb Aug 28 '17 at 12:08
  • Do you suggest to create another keystore and then use it with KeyChain API? Do you know is it possible to generate private key inside keystore? I managed do it only with AndroidKeyStore. – macieg_b Aug 28 '17 at 14:21
  • You can generate directly a key pair, public and private using `KeyPairGenerator`. A key and the certification chain can be stored later into a `KeyStore` and serialized as PKS12. You can see a similar example here https://stackoverflow.com/questions/13207378/saving-certificate-chain-in-a-pkcs12-keystore . – pedrofb Aug 28 '17 at 19:36
  • 1
    Yes but the problem is how to safetly store private key waiting for certificate - without chain i can't store only PrivateKey that's why I wonder how to use AndroidKeyStore or how to generate PrivateKey which can be serialize (AndroidKeyStore cannot be serialize). – macieg_b Aug 28 '17 at 19:39
  • Good question, because in many cases you can not control how long the CA takes: encrypt the keystore with a key managed with `AndroidKeyStore` or save it with a password – pedrofb Aug 28 '17 at 19:47
  • Encryption of keystore doesn't help because in this situation keystore is useless: I can store there only Private Key with CHAIN. I haven't found good solution. – macieg_b Aug 29 '17 at 04:31
  • You encrypt the keystore until the CSR is received, then decrypt it with the previously generated key, import the received certificate and export it as pkcs12. This keystore file would only be used as temporal storage. You could also store the private key in SharedPreferences – pedrofb Aug 29 '17 at 06:04
  • 1. Why do you talk about keystore encryption if the keystore is empty? 2. I use SharedPreferences, they are encrypted using AES but I want to find better option. – macieg_b Aug 29 '17 at 06:07
  • Encryption of a keystore file is not a problem but insert only a private key is. – macieg_b Aug 29 '17 at 06:08
  • 1. You encrypt the keystore after inserting the private key, so it is not empty. 3. See the link i posted. The key is inserted with a dummy certificate which can be discarded later. Probably the SharedPreferences solution is cleaner and simpler – pedrofb Aug 29 '17 at 06:15

1 Answers1

0

I too had similar requirement where in I had to retrieve the Private Key from the Keystore and I was getting the same error as yours. However, after that I tried not using KeyGenParameterSpec while storing the key in Android keystore and it worked for me. Check my code below , it might help you

Storing Key in Android Keystore :

 KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
 keyPairGenerator.initialize(2048);
 KeyPair keyPair = keyPairGenerator.generateKeyPair();
 PrivateKey privateKey = keyPair.getPrivate();
 keyStore.load(null);

 X509Certificate certificate = generateCertificate(keyPair, null);
 Certificate[] certChain = new Certificate[1];
 certChain[0] = certificate;

 keyStore.setKeyEntry(Constants.KEY_ALIAS, privateKey, null, certChain);

Here X509Certificate is my self signed certificate which I am generating using X509V3CertificateGenerator.

Retrieving Private Key from Keystore :

KeyStore ks = KeyStore.getInstance("AndroidKeyStore");
ks.load(null);
KeyStore.Entry entry = ks.getEntry(Constants.KEY_ALIAS, null);

if (entry == null) {
    Logger.w(getClass().getName(), "No key found under alias: " + Constants.KEY_ALIAS);
    Log.w(getClass().getName(), "Exiting signData()...");
    return null;
}

if (!(entry instanceof KeyStore.PrivateKeyEntry)) {
    Log.w(getClass().getName(), "Not an instance of a PrivateKeyEntry");
    Log.w(getClass().getName(), "Exiting signData()...");
    return null;
}

PrivateKey privateKey = ((KeyStore.PrivateKeyEntry) entry).getPrivateKey();
AaA
  • 3,600
  • 8
  • 61
  • 86
  • Yes, it's the best option that I found in another subject. All we can do in this situation: 1. Generate KeyPair not in AndroidKeyStore but ouside. 2. Create Keystore - for example PKCS12 keystore. 3. Make self-signed certificate. 4. Set keyEntry into keystore. 5. Get real Certificate from CA and set KeyEntry again. 5. Transform PKCS12 into byte[] / stream 6. Install certificate. – macieg_b Aug 31 '17 at 07:46
  • Yes buddy. Upvote/Accept the answer if u feel right :) – Sankalp Pandya Aug 31 '17 at 09:19
  • @macieg_b note that after you've created your CA you can import the private key into AndroidKeyStore, which will keep the private key material in secure hardware thereafter. – divegeek Jan 30 '19 at 23:13