Search code examples
javaandroidencryptionandroid-keystore

How to store RSA Private Key into app given by backend?


I am developing an android app, in which I have to use payload encryption. For this backend giving me a pre generated key pair (RSA Public and Private key) for encryption and decryption.

As of now I am keeping these 2 keys (RSA public and private) in string hardcoded, but everyone knows that it's not a secure way to do this.

So in this process, client will send the request encrypted using server's public key, and server will decrypt it using their own private key. And the response can be decrypted only by client's private key because it was encrypted by client's public key.

Note - RSA public & private key will be static for my app, and I want to manage it put in a secure place.

So the main problem is where should I keep that private key in my app. Key is static in my app because server people distribute it to mobile team. And we can not use our self generated private key.

So what can be the best way to secure this first time givin private key at client side.

I tired this link & this, but none suitable for me.

Happy coding :-)


Solution

  • Probably you should change your server approach to public key exchange and generate key separately on android device. This way would be much secure.

    You must store private keys with a certificate in KeyStore. Here are steps how you can achieve this:

    Step 1. Decode the Base64 PKCS#8 to get an instance of PrivateKey:

    PKCS8EncodedKeySpec ks = new PKCS8EncodedKeySpec(privateKeyBytes);
    KeyFactory kf = KeyFactory.getInstance("RSA");
    PrivateKey privateKey = kf.generatePrivate(ks);
    

    Step 2. The case might be that your server sends a certificate with private key or PKCS#8 blob also contains the public key.

    Step 3. If server does not send certificate, you'll need to generate certificate for private key. Here is example using BouncyCastle.

    Step 4. Store key on KeyStore:

    X509Certificate certificate = ... // get certificate for private key or generate
    KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
    keyStore.load(null);
    keystore.setKeyEntry("MyAlias", privateKey, null, new Certificate[] { certificate });
    

    If you really have to transmit private key to device from server, more secure case might be following:

    1. Generate AES key on device.
    2. Get server's public key first.
    3. Wrap generated AES key using that public key.
    4. Transmit encrypted AES key to server.
    5. Decrypt encrypted AES key on server side using private key.
    6. Encrypt private key using AES key, and transfer it to device.

    The question was updated, so updated answer:

    If you have to keep public private keypair in the app, I'd recommend keeping bytes of key using Android NDK, and strongly obfuscating it.

    However, if I were you, as obfuscation tools are expensive for strong Android C++ code encryption, I'd keep those static key on server side, not hardcoded inside app. Then I'd send static key to device using the steps I mentioned before using symmetric encryption.

    But if you choose using NDK option, it's better than storing key on file or on Java code also, but not fully bulletproof. Once user opens the app, you can store the key retrieved from C++ code in KeyStore, so, you make sure it's safe.

    So, if you want to go with fastest option for keeping private key secure inside app binary, go for NDK option, and in future you can obfuscate it. If you have time to do some server side arrangements for transmitting private key, then storing on keystore, then go for steps I wrote.

    Here are few resources might help you for NDK:

    https://androidsecurity.info/2016/12/15/storing-your-secure-information-in-the-ndk/

    https://medium.com/@abhi007tyagi/storing-api-keys-using-android-ndk-6abb0adcadad/