Signing an Android App

By | 2015-02-19

Before you release you’ll need to sign your .apk file. The guide from Google implies that you should make a single key for your identity, and sign all your apps with that key. I recommend against that. You should make a key per app. The reason I suggest that is because one day you might want to hand over responsibility for that app to another company or developer, or, the lottery win, a company wants to buy the whole thing from you. In that case, if you have a company-wide key, then you’re handing over keys to all your apps, not just one.

For all of this I’ll assume you already have the Android SDK installed. You’ll also need a JRE package for the keytool and jarsigner tools.

Let’s say then that you’re signing MegaApp.apk. First you should generate an individual key store just for this app.

$ keystore -genkey -v \
    -keyalg RSA -keysize 2048 -validity 10000 \
    -keystore megaapp.jks \
    -alias megaapp
Enter keystore password:  
Re-enter new password: 
What is your first and last name?
  [Unknown]:  MegaApp
What is the name of your organizational unit?
  [Unknown]:  Android Apps
What is the name of your organization?
  [Unknown]:  FussyLogic Ltd
What is the name of your City or Locality?
  [Unknown]:  Cheshire
What is the name of your State or Province?
  [Unknown]:  England
What is the two-letter country code for this unit?
  [Unknown]:  GB
Is CN=MegaApp, OU=Android Apps, O=FussyLogic Ltd, L=Cheshire, ST=England, C=GB correct?
  [no]:  yes

Generating 2,048 bit RSA key pair and self-signed certificate (SHA256withRSA) with a validity of 10,000 days
        for: CN=MegaApp, OU=Android Apps, O=FussyLogic Ltd, L=Cheshire, ST=England, C=GB
Enter key password for <megaapp>
        (RETURN if same as keystore password):  
[Storing megaapp.jks]

We’re going to store one key per keystore, so we name the key and the keystore both megaapp (this makes it easier to remember what alias you used :-)). You can, of course, pick your keystore password as you wish to match the security of your organisation – however, I suggest you treat the keystore file itself as the secure element, and make the password the same as the alias, “megaapp” (we’ll see why below). You can pick the DN (distinguished name) as you please, my recommendation is not to put your own name when asked, but to put the name of the app again.

We’ve got a 2048 bit key, valid for 10,000 days (27 years), stored in a keystore file under an alias and password the same as the keystore name. Obviously this file has very poor internal security – so you must be very circumspect in where you store and who you give access to this file.

What I’d like to describe is using a continuous integration system (I like Jenkins) to build and sign a release-ready version of your apk. For that reason we’re going to do everything on the command line so that you can reproduce the process in your build server’s scripts.

Build your app. Here’s how I do it:

cd your/app/directory
rm -f build.xml
rm -f local.properties
android update project --name "MegaApp" --path .
ant clean
ant release

The ant release command builds you an unsigned .apk (unlike the ant debug command, which builds an .apk signed with the debug key, which is unsuitable for release to the Play store). If you have a more complicated app, perhaps with libraries, you may want to copy or symlink them in this sequence too.

We’re now in a position to produce a signed .apk. It’s all boilerplate, so you will substitute your app name where appropriate.

# input parameters
APKNAME=MegaApp
KEYALIAS=megaapp

# standard form of files and aliases
KEYSTORE=${KEYALIAS}.jks
STOREPASS=${KEYALIAS}
KEYPASS=${KEYALIAS}
UNSIGNED=bin/${APKNAME}-release-unsigned.apk
SIGNED=bin/${APKNAME}-release-signed.apk
ALIGNED=${APKNAME}.apk

# generate signed-but-unaligned apk
jarsigner -verbose \
    -sigalg SHA1withRSA -digestalg SHA1 \
    -keystore ${KEYSTORE} \
    -storepass ${STOREPASS} \
    -keypass ${KEYPASS} \
    -signedjar "${SIGNED}" \
    "${UNSIGNED}" ${KEYALIAS}
# check signing worked
jarsigner -verify -verbose -certs "${SIGNED}"
# create aligned apk from signed apk
zipalign -v 4 "${SIGNED}" "${ALIGNED}"

I’m presenting this in a form that cuts-and-pastes into a script, with only a couple of name changes at the top to make it suit your app.

Hopefully you see the logic in using such an insecure password – if we had used a secure password, we would have had to write it, plain text, in this script anyway so that the signing could be automated – so what security would we actually have gained? Someone with access to the key store would have access to this script, and hence would have the password anyway.

Importantly: the keystore is now your signing security – if you lose control of that then others can tell your users that any arbitrary .apk they produce is actually an upgrade to your app. Keep this file safe.

Feel free to combine the build and sign snippets into a single file.

As I said, I have, essentially, this script on my Jenkins build server for my Android apps – that server is never exposed to the public internet. On completion the signed app is copied to a web server were my clients can download it at their leisure – the advantage of a signed app is that your users can rely on upgrades being a trusted chain. Of course you can also upload the .apk to the Play store.

Leave a Reply