Showing posts with label public key. Show all posts
Showing posts with label public key. Show all posts

27 October 2019

Enrol on App Signing in the Google Play Store for existing Android App

App Signing by the Google Play Store is on the face of it an incredibly brilliant idea. I absolutely love it. However I found it impossibly difficult to follow Google’s rather short documentation on how to get setup, especially for existing app users. So I thought I’d write this little helper to try and spell it out to anyone who tries to follow the same process I have.

App signing is the process of creating a keystore with which you sign your Android app and verify it is in fact you who is releasing an update to your Android app. A keystore remember is basically just a special store for a private and a public key.

If you lose the original master keystore you signed your app with, bad news. You need to create a new app and a new Google Play Store listing. Not fun.

The concept of App Signing for Google Play Store is basically that you surrender the master keystore that you used to sign your initial app to Google (let’s call this the release key). Google then securely stores and manages your release key. You then create a brand new keystore called an upload key. You do this as if you were creating a brand new app, through Android Studio or if you’re a keyboard warrior, using java keytool. You then tell Google about this upload key and you’re done. All future releases can be signed with your upload key and Google will re-sign with the original, now super secret and secure release key. The benefit of this is Google keeps everything secure, and if you lose or compromise your upload key, Google will let you discard it and create a new one. Your users are none the wiser and everyone is happy all of the time.

The process for implementing all this is a little more complicated, first you need to head the play store and goto “App signing” under “Release management”.




Now we need to get all our keystores, private keys, certificates and koala bears in some sort of order. I’m doing this in Android Studio 3.5, older versions may need an upgrade.

First step we need to extract the private key from your original master release key.

Step 1 - Get an App Signing Private Key

Open your app in Android Studio and ensure it builds

  1. Goto Build -> Generate Signed Bundle / APK (Don’t worry you don’t need to actually release this build)
  2. Even if you’re not wanting to use App Bundle, select Android App Bundle and click next.
  3. Enter the details for your master, original release key, including store password, alias and key password
  4. IMPORTANT -> check “Export encrypted key for enrolling published apps in Google Play App Signing”
  5. Finish off the process and make a build. You should now have a pepk file which is the private key for your original master release key.


Now we need to generate a brand new upload key to use to sign our future apps.

Step 2 - Create an upload key


  1. Again goto Build -> Generate Signed Bundle / APK (Again not actually going to release an app)
  2. Select APK or App Bundle, whichever you would normally do.
  3. Click “Create new…”, we’re going to create a new keystore.
  4. Fill in all the details and make the build.
  5. You should now have a brand new keystore with brand new passwords and an alias. KEEP THIS CAREFULLY.
  6. This keystore will be used forevermore as your main key to release your apps.


Now we need to get a public key from our new upload key, this will be how we tell Google about our new upload key.

Step 3 - Generate a Public Certificate


  1. Use keytool and run a command like this
    keytool -export -rfc -keystore upload-keystore.jks -alias upload -file upload_certificate.pem
  2. Use your NEW UPLOAD KEY for “upload-keystore.jks” and your new alias 
  3. Keytool is usually somewhere in jdk/bin
  4. After running this command you should have a .pem file.


Now go back to the Google Play Store and click “Upload a key exported from Android Studio” now you can add your private key and your public certificate. This gives Google the details of the release key and the upload key and you should be all set.

Click finish and you should now be signed up to App Signing. Well done, keep a close eye on that upload key and it’s passwords.

01 March 2015

Security isn't a dirty word Blackadder

Hopefully we all understand the concepts behind asymmetric (Public / Private key) encryption. It’s something we use all the time (https, SSL etc) but I've never actually put code to screen and tried to implement it. I've always relied on standard symmetric-key algorithm. So I thought I’d give it a go in Java / Android and along the way I learned a lot. In this blog article I thought I’d outline a few things I've learned. I’ll put some code up as I go, but I’d like to try and focus a bit more on the lessons.
All security is equal, except some more equal than others
We all know in symmetric encryption DES is bad, right?
DES is now considered to be insecure for many applications
http://en.wikipedia.org/wiki/Data_Encryption_Standard#Brute_force_attack


Well in theory public / private key encryption is infinitely better as long as you never give out your private key. Easy peasy, so we choose one of these and away we go:
  • RSA
  • EIGamal
  • Diffie-Helman
So I want to take a basic string “All your base are belong to me” and I want to encrypt it using a public key and decrypt it using a private key.
Rush to code

Impatient as I am I rush to get some code in and find this code to try out:
byte[] data = readBytesFromfile(“mypublickey”);
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(data); 
KeyFactory kf = KeyFactory.getInstance("RSA");
pubKey = kf.generatePublic(keySpec);

Great, now I need a public and private key to test my amazing new code.

I learn a few bits about encryption

I’d heard of PGP and apparently this has no known weaknesses, perfect, I want this! So away I go and find a tool to generate my PGP public and private key. I throw these into my java code and straight away get an error. Hmmm. Something doesn't feel right here. Plus I'm not too sure about PGP and OpenPGP. OK back to wikipedia. Apparently PGP is a protocol, not an algorithm and for its asymmetric files it uses RSA anyway! Doh! So I resort to RSA and now I need to generate an RSA key.


So I've already got puttyGen installed and it I don’t know why it says SSH but it definitely says RSA right there with a big button saying “Generate”. Boom, surely this will work, nothing can stop me now!
Now I get a java error InvalidKeySpecException
Hmm, after some serious time googling I ask stack overflow
http://stackoverflow.com/questions/28218636/invalidkeyspecexception-using-public-key
Although it doesn't solve my problem, Maarten alerts me to the fact that in java I need to use the X509 format.
Hang on SSH is a protocol isn't it? (Back to wikipedia). Right ok so PGP and SSH are protocols that implement asymmetric encryption using the RSA algorithm. I don’t want a protocol, I want to just generate an encrypted string.


To do that I need a public key which java can read. So all I need is to generate a key in the right format….That makes sense.

Using KeyTool and OpenSSL to generate a 509 certificate


This doesn't take me long using java keytool and openssl to generate an x509 certificate.
keytool -genkey -keyalg RSA -keysize 1024 -keystore C:\temp\hello.keystore

keytool -importkeystore -srckeystore C:/temp/hello.keystore -destkeystore C:/temp/hello.p12 -deststoretype PKCS12

openssl pkcs12 -in C:/temp/hello.p12 -out C:/temp/hellonew.pem -nodes

openssl x509 -in C:/temp/hellonew.pem -inform PEM -out C:/temp/hellodernew.der -outform DER

Reading an X509 certificate
Now we need to adapt our code to read the key in the new format.
public static PublicKey getPublicKey(byte[] keyBytes){
    PublicKey publicKey = null;

    if(keyBytes != null) {

        X509EncodedKeySpec spec = new X509EncodedKeySpec(keyBytes);
        KeyFactory kf = null;
        try {
            kf = KeyFactory.getInstance("RSA");
            publicKey = kf.generatePublic(spec);
        } catch (NoSuchAlgorithmException e) {
            Log.e(TAG, "NoSuchAlgorithmException");
            e.printStackTrace();
        } catch (InvalidKeySpecException e) {
            Log.e(TAG, "InvalidKeySpecException " + e.getMessage());
            e.printStackTrace();
        }
    }

    return publicKey;
}

This means we can now use our PublicKey to encrypt our message! Wohoo


Decryption

To decrypt we use a similar function

    public static PrivateKey getPrivateKey(byte[] keyBytes){
        PrivateKey privatekey = null;

         if(keyBytes != null) {
            PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(keyBytes);
            KeyFactory kf = null;
            try {
                kf = KeyFactory.getInstance("RSA");
                privatekey = kf.generatePrivate(spec);
            } catch (NoSuchAlgorithmException e) {
                Log.e(TAG, "NoSuchAlgorithmException");
                e.printStackTrace();
            } catch (InvalidKeySpecException e) {
                Log.e(TAG, "InvalidKeySpecException");
                e.printStackTrace();
            }
        }

         return privatekey;
    }


Encrypting a large file

For various reasons I've also learned you can’t just encrypt a file with your public key. This guy gives an excellent description of what you should be doing:


The basic idea is as such:
  1. Create a session key using symmetric encryption, AES for example.
  2. Then encrypt the file using this session key
  3. Using your public key encrypt the session key
  4. Send the AES encrypted file and the public key encrypted session key together
  5. Your server / recipient uses the private key they have and decrypts the session key then using that decrypts the file.


This method allows for fast encryption and secure transmission. If anyone brute forces the session key, they've only ever got one file. They need to start again for every single new file!

Anyway, that’s about what I've learned on this particular journey. I hope its of some help.