1

I've stumpled upon following Problem:

I need to create a KeyPair where I need to access the PrivateKey's getEncoded() once, before inserting it into the AndroidKeyStore.

When generating a Key via AndroidKeyStore, the resulting Keys getEncoded() method returns null (as intended as an extra key protection mechanism).

This is how I generate a Key using a KeyGenParameterSpec (targeting only devices above Android.M):

public AlgorithmParameterSpec createSpec(){

    Calendar start = new GregorianCalendar();
    Calendar end = new GregorianCalendar();
    end.add(Calendar.YEAR, 1);
    String alias = "myKeyAlias";

    AlgorithmParameterSpec spec = new KeyGenParameterSpec.Builder(alias,
    KeyProperties.PURPOSE_SIGN | KeyProperties.PURPOSE_VERIFY | 
    KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
                    .setCertificateSubject(new X500Principal("CN=" + alias))
                    .setDigests(KeyProperties.DIGEST_SHA256)
                    .setSignaturePaddings(KeyProperties.SIGNATURE_PADDING_RSA_PKCS1)
                    .setCertificateSerialNumber(BigInteger.valueOf(1337))
                    .setCertificateNotBefore(start.getTime())
                    .setCertificateNotAfter(end.getTime())
                    .build();
   return spec;
}

public KeyPair generateKeyPairInKeystore(AlgorithmParameterSpec spec){
    KeyPairGenerator kpGenerator = KeyPairGenerator
            .getInstance("RSA", "AndroidKeyStore");
    kpGenerator.initialize(spec);

    KeyPair kp = kpGenerator.generateKeyPair();
    //here kp.getPrivate().getEncrypted() doesn't give me the key
    return kp;
}

public KeyPair generateKeyPair(AlgorithmParameterSpec spec){
    KeyPairGenerator kpGenerator = KeyPairGenerator
            .getInstance(SecurityConstants.TYPE_RSA);
    kpGenerator.initialize(spec);

    KeyPair kp = kpGenerator.generateKeyPair();
    //I cannot receive the encrypted Key here either
    //kp.getPrivate().getEncrypted();
    return kp;
}

These Keys are generated inside AndroidKeyStore so they are automatically stored there. But I cannot access getEncrypted() to send it to a trusted Server.

So what I'm missing is:

  1. How to create a PrivateKey where getEncoded() is accessible?
  2. How do I store it inside Androids secure KeyStore (as I need to provide Certificates along)?
Phantômaxx
  • 37,901
  • 21
  • 84
  • 115
Rafael T
  • 15,401
  • 15
  • 83
  • 144
  • 1
    The `AndroidKeyStore` is designed to create non-exportable keys. If you need to get access to the private key data don't create them in the AndroidKeyStore, create it outside. If you want you can later import it into the AndroidKeyStore. – Robert Feb 12 '19 at 16:24
  • @Robert sure, that was my question. I tried all Providers in Security.getProviders(), getting all sorts of errors (some don't generate RSA keys (AndroidOpenSSL) while others (Bouncy castle) seems deprecated. Can you give a small code example of how to create an accessible KeyPair and storing it afterwards? – Rafael T Feb 12 '19 at 16:44
  • You don't have to specify the provider, just generate an RSA keypair: https://stackoverflow.com/a/1710112/150978 – Robert Feb 12 '19 at 18:43
  • @Robert As i did in my second generateKeyPair function? I didn't input a provider there at all, but then AndroidKeyStore is chosen by default (as mentioned). The sample you provided just inits it with a int(512) so I cannot enter certificate parameters – Rafael T Feb 12 '19 at 21:19
  • A KeyPairGenerator just generates key pairs, not certificates therefore it only need the key size. The "AndroidKeyStore" by Google is the unusual one as it not only generates keys but also certificates. If you need a certificate use the generated key pair to build one yourself. – Robert Feb 13 '19 at 08:37
  • You could use another software provider (indeed, e.g. a separate downloaded Bouncy Castle provider) and get an encoded version of the keys generated with that. I haven't posted an answer because I have no idea if you can actually *import* those keys into the Android key store. The problem is that such keys are "tainted" as they may have been exposed to adversaries *before* they are imported, so the protection of the key store may not be present. Otherwise storing them outside the (Android) key store seems the sensible option, indeed. – Maarten Bodewes Feb 13 '19 at 17:24
  • It should be possible to create a self signed cert using the Bouncy Castle lightweight API, by the way. That way you can create a chain of one certificate that belongs to your private key. Good luck! – Maarten Bodewes Feb 13 '19 at 17:29
  • @Maarten Bodewes I know about the risks of exposed keys, but real world software requirements are almost always weird :( I know for sure that you can put self generated AES Keys into Androids KeyStore, so I might give spongyCastle a try (If I can't convince the customer that it's better to never expose them). But I guess the answer to my question is "you don't" ;) – Rafael T Feb 13 '19 at 23:27
  • Spongy was required when the BC API was directly included into Android. It may be possible to directly use BC by now if your API is high enough and the *stripped* BC runtime has been moved to a different package name or removed altogether (or a combination of the two). – Maarten Bodewes Feb 14 '19 at 00:20

0 Answers0