wiki:Android/SigningFirmwareUpdateZipAndApkPackages

Signing Firmware Update.zip and APK Packages

Work In Progress

When shipping updated Android firmware images (often named update.zip but can be anything) or Application PacKages (APKs) it is necessary to cryptographically sign the files to verify they are issued by you and have not been tampered with. Files provided to other users should be signed with a Release key that is well-protected locally. This article describes how to configure a key-signing system for Android and use it (The  Android documentation also covers this subject for application signing).

APK files are similar to Java ARchive (JAR) files and both are standard ZIP archives that use a prescribed directory and file lay-out internally. The signing of one of these ZIP archives just means that the cryptographic signature of all the files included in the archive is calculated and then written into a file that is added to the archive.

Prerequisites

The Java Software Development Kit (J-SDK) includes two tools for creating and using cryptographic keys:  keytool and  jarsigner. On a Linux system they should already be in the executable search PATH.

$ which keytool jarsigner
/usr/bin/keytool
/usr/bin/jarsigner

On Debian/Ubuntu these are symbolic links; the real executables can be found using this shell script that follows all symbolic links typically used by the update-alternatives program. This helps to determine which SDK version the tools are from since the tools do not report their version (later versions will include bug fixes and greater functionality):

$ which keytool jarsigner | while read filename; do while (true) do link=$(readlink $filename); echo "link: $filename > $link"; if [ -L "$link" ]; then  filename=$link; else break; fi; done; echo "file: $link"; done

link: /usr/bin/keytool > /etc/alternatives/keytool
link: /etc/alternatives/keytool > /usr/lib/jvm/java-6-openjdk/jre/bin/keytool
file: /usr/lib/jvm/java-6-openjdk/jre/bin/keytool
link: /usr/bin/jarsigner > /etc/alternatives/jarsigner
link: /etc/alternatives/jarsigner > /usr/lib/jvm/java-6-openjdk/bin/jarsigner
file: /usr/lib/jvm/java-6-openjdk/bin/jarsigner

The Android Software Development Kit (A-SDK) contains the  zipalign tool which ensures APKs have uncompressed binary resources aligned on 32-bit boundaries so that the mmap (memory-map file) function can be used to directly address the contents, and to reduce RAM usage.

$ which zipalign
/usr/local/lib/android-sdk-linux_86/tools/zipalign

Create a Release Signing Key

Create a new key for signing that doesn't expire for 10,000 days (> 27 years) with a memorable alias:

keytool -genkeypair -v -validity 10000 -alias tjworld -keyalg RSA -keysize 2048 -keystore $HOME/.android/release.keystore  

Enter keystore password:  
Re-enter new password: 
What is your first and last name?
  [Unknown]:  TJ
What is the name of your organizational unit?
  [Unknown]:  Android Development
What is the name of your organization?
  [Unknown]:  TJworld
What is the name of your City or Locality?
  [Unknown]:  Vale of Belvoir
What is the name of your State or Province?
  [Unknown]:  Nottinghamshire
What is the two-letter country code for this unit?
  [Unknown]:  UK
Is CN=TJ, OU=Android Development, O=TJworld, L=Vale of Belvoir, ST=Nottinghamshire, C=UK correct?
  [no]:  yes

Generating 2,048 bit RSA key pair and self-signed certificate (SHA1withRSA) with a validity of 10,000 days
	for: CN=TJ, OU=Android Development, O=TJworld, L=Vale of Belvoir, ST=Nottinghamshire, C=UK
Enter key password for <tjworld>
	(RETURN if same as keystore password):  
Re-enter new password: 
[Storing release.keystore]

The keystore should be secured by making the key-store readable only by the super-user (to prevent any processes running with your user credentials gaining access to it). This will then require use of sudo to access it:

$ cd $HOME/.android
$ chmod 400 release.keystore 
$ sudo chown root:root release.keystore

$ ls -l
total 20
-rw-r--r-- 1 tj   tj    123 2011-06-09 21:52 adb_usb.ini
drwxr-xr-x 2 tj   tj   4096 2010-07-04 07:45 avd
-rw-r--r-- 1 tj   tj    100 2011-06-09 21:37 ddms.cfg
-r-------- 1 root root 2246 2011-06-16 17:22 release.keystore
-rw-r--r-- 1 tj   tj     72 2011-06-09 21:52 repositories.cfg

$ wc -l release.keystore
wc: release.keystore: Permission denied

$ sudo wc -l release.keystore
16 release.keystore

Create a Debug Signing Key

The debug certificate should have a short lifetime - an expiry of 60 days is usually more than enough. There is also not so much need to secure the signing key or keystore since the purpose is for non-public development debugging. Therefore the procedure can be relaxed somewhat. For one thing the keystore password can be kept in a file that can be read by scripts to save the developer typing it manually:

pwgen -s 16 1 > $HOME/.android/debug.passwd

Then to create the debug signing key:

keytool -genkeypair -v -validity 60 -alias tjworld -keyalg RSA -keysize 2048 -keystore $HOME/.android/debug.keystore -storepass $(cat $HOME/.android/debug.passwd)
What is your first and last name?
  [Unknown]:  TJ
What is the name of your organizational unit?
  [Unknown]:  Android Development Debugging
What is the name of your organization?
  [Unknown]:  TJworld
What is the name of your City or Locality?
  [Unknown]:  Vale of Belvoir
What is the name of your State or Province?
  [Unknown]:  Nottinghamshire
What is the two-letter country code for this unit?
  [Unknown]:  UK
Is CN=TJ, OU=Android Development Debugging, O=TJworld, L=Vale of Belvoir, ST=Nottinghamshire, C=UK correct?
  [no]:  yes

Generating 2,048 bit RSA key pair and self-signed certificate (SHA1withRSA) with a validity of 60 days
    for: CN=TJ, OU=Android Development Debugging, O=TJworld, L=Vale of Belvoir, ST=Nottinghamshire, C=UK
Enter key password for <tjworld>
    (RETURN if same as keystore password):  
[Storing debug.keystore]

Signing Helper Tool

Add a script into the executable search PATH (e.g. /usr/local/bin/) that makes an easy-to-remember one-command operation to sign packages. Attached to this article is android-signer Download, a script I created to automate the signing of firmware updates. It can also be used to manually sign and zip-align APKs.

android-signer -h
Usage: android-signer [-d | -r] -i <input.zip> -o <signed.zip>
	-a alias of key to sign with
	-d sign with DEBUG key
	-r sign with RELEASE key
	-h show this help
	-i <input.zip> name of ZIP/APK file to sign
	-o <output.zip> name to give to signed ZIP/APK
	-v version

Here's an example of using it to sign an APK using the debug key:

android-signer -d -a tjworld -i test.apk
TYPE apk
   adding: META-INF/MANIFEST.MF
   adding: META-INF/TJWORLD.SF
   adding: META-INF/TJWORLD.RSA
  signing: AndroidManifest.xml
  signing: classes.dex
   adding: res/

Warning: 
The signer certificate will expire within six months.
Aligning ZIP file...
Verifying test.apk

         207 Fri Jun 17 15:09:10 BST 2011 META-INF/MANIFEST.MF
         328 Fri Jun 17 15:09:10 BST 2011 META-INF/TJWORLD.SF
        1415 Fri Jun 17 15:09:10 BST 2011 META-INF/TJWORLD.RSA
           0 Thu Jun 16 22:53:00 BST 2011 META-INF/
smk        5 Thu Jun 16 22:53:14 BST 2011 AndroidManifest.xml

      X.509, CN=TJ, OU=Android Development Debugging, O=TJworld, L=Vale of Belvoir, ST=Nottinghamshire, C=UK (tjworld)
      [certificate will expire on 15/08/11 21:56]

smk   524288 Thu Jun 16 22:54:28 BST 2011 classes.dex

      X.509, CN=TJ, OU=Android Development Debugging, O=TJworld, L=Vale of Belvoir, ST=Nottinghamshire, C=UK (tjworld)
      [certificate will expire on 15/08/11 21:56]

           0 Thu Jun 16 22:53:18 BST 2011 res/

  s = signature was verified 
  m = entry is listed in manifest
  k = at least one certificate was found in keystore
  i = at least one certificate was found in identity scope

jar verified.

Warning: 
This jar contains entries whose signer certificate will expire within six months. 
Verifying alignment of test.apk (4)...
      50 META-INF/MANIFEST.MF (OK - compressed)
     288 META-INF/TJWORLD.SF (OK - compressed)
     595 META-INF/TJWORLD.RSA (OK - compressed)
    1768 META-INF/ (OK)
    1844 AndroidManifest.xml (OK)
    1914 classes.dex (OK - compressed)
  526436 res/ (OK)
Verification succesful

Signed file: test.apk

Attachments