The following is the first few sections of a chapter from The Busy Coder's Guide to Android Development, plus headings for the remaining major sections, to give you an idea about the content of the chapter.


Miscellaneous Security Techniques

This chapter outlines some additional security measures that you can consider for your applications that do not necessarily warrant a full chapter on their own at this time.

In other words, it’s just a pile of interesting security stuff.

Prerequisites

Understanding this chapter requires that you have read the core chapters of this book. In addition, you should review the app signing chapter if you are unfamiliar with the signing process.

Public Key Validation

We sign our apps with signing keys all the time. By default, we are signing with a so-called “debug signing key”, created automatically by the build tools. For production, we sign with a different signing key. The primary use of that signing key is to determine equivalence of authorship:

However, as it turns out, information about the public key that signed an APK is visible to us, for our own APK as well as for any other APK on the device. We can leverage that to help determine whether a given APK was signed by something we recognize. This goes above and beyond using Android’s built-in signature-based defenses (e.g., using a custom signature-level permission).

Scenarios

There are several scenarios in which we might imagine that we could employ our own public key validation. How well the technique will work, though, depends on what we are checking and the nature of the attack we are defending against.

Checking Yourself

You might consider checking your own app’s public key. After all, if your app is not signed with your production signing key, something very strange is going on, and the natural reaction is that “something strange” is unlikely to be a good thing for you.

However, there are some issues here.

First and foremost, checking your own signing key assumes that whatever caused you to not be signed by that key did not also modify your validation algorithm. For example, suppose that you validate your signing key to determine if somebody perhaps reverse-engineered and modified your app, perhaps to remove some license checks. This will only catch an attacker that removed the licensing checks and did not also remove your signature validation, or modify the validation to use the attacker’s signing key. While it is possible that an attacker will modify one part but not another, it remains unclear how well this defense will work in practice.

Also, bear in mind that you, as a developer, may be opting into services that intentionally change your app’s signature. Various providers will “wrap” your app, whether for interstitial ad banners or for quasi-DRM. There are three possible ways that they wrap your app:

  1. They sign it with their signing key, which means that your runtime validation of the key will fail, as your app is now signed by their key, not yours. This is also very risky, as if for whatever reason you are no longer able to use their service (e.g., they go out of business), you may have difficulty in upgrading your app, as you will not have the right key to use.
  2. They sign it with your signing key, either one that you upload, or one that they generate for you. In this case, your runtime public key validation logic could still work. On the other hand, now this other firm is perfectly capable of upgrading your app, or shipping other apps, signed with your production signing key, and this has its own set of risks.
  3. They allow you to download the “wrapped” app and have you sign it yourself with your own signing key. This is the best alternative from a security standpoint, but it is the most tedious, as now you have additional work to do to publish your app.

Checking Arbitrary Other Apps

What will tend to be more reliable is to check other applications’ public keys. While they might have been cracked, it is unlikely that the same attacker also attacked your app, and so you can help detect problems in others.

For example, let us consider a specific scenario: a client-side JAR for integration to a third-party app.

This book outlines many forms of IPC, from content providers to remote services to broadcast Intent objects. If you are creating an app that offers such IPC endpoints, you may wish to consider also shipping a JAR to make using those endpoints a bit easier. You might create a library that handles all of the details of sending commands to your remote service, or you might create a library that provides a wrapper around the AIDL-generated Java proxy classes for remote binding.

Another thing such a JAR could do is check the integrity of your app. The JAR’s code is in the client’s app, not yours, and while your app might be cracked, the client’s app might not. You could check the validity of the public key of your own app from the client’s app, and fail if there is a detected problem.

This might be especially important depending upon the nature of the app and the JAR that is providing access to it. If the app is an app offering on-device payments (e.g., a Google Wallet sort of app), and the app offers an API for other apps to do payments, it is fairly important that those other apps can trust the payment app. By checking the public key, your JAR can help provide that level of trust… or at least ensure that nobody else has done something specifically to degrade that trust.

This is particularly important for avoiding device-hosted man-in-the-middle attacks on your IPC from client apps to your app. In an ideal world, you would only allow IPC via signature-level permissions, but that will not work in cases where third parties are writing the clients.

If your IPC is based upon a service (command pattern or binding pattern), if multiple service implementations all advertise the same <intent-filter>, Android needs to decide which service will handle the request. First, it will take into account the android:priority value on the <intent-filter> (even though this behavior is currently undocumented). For multiple services with the same priority (e.g., no priority specified), the first one that was installed will be the one that is chosen. In either case, the client has no way to know, short of examining the service’s public key, whether the service that will respond to the requests for IPC is the legitimate service or something else advertising that it supports the same Intent action. Even with Android 5.0 blocking your ability to bind via an implicit Intent, you wind up with the same sorts of problems when you use resolveService() to try to determine the ComponentName of the service to make an explicit Intent for it.

The Easy Solution: SignatureUtils

The author of this book has published the CWAC-Security library. Among other things, this library has a SignatureUtils class that makes it relatively easy for you to compare the signature of some Android app to a known good value.

All you need to do is call the static getSignatureHash() method, supplying some Context (any will do) and the package name of the app that you wish to check. This will return the SHA-256 hash of the signing key of the app, as a set of capitalized, colon-delimited hex values.

You can get the same sort of hash by running the Java 7 version of keytool. Hence, if the app you wish to test is another one of yours, perhaps signed with a different signing key, you can use keytool to get the value to compare with the result of getSignatureHash(). Or, during development, create a little utility app that will dump the getSignatureHash() value for the third-party app, and run it on a device containing a known good version of that app (i.e., one that does not appear to have been replaced by malware).

Ideally, over time, we will be able to get app developers to publish their SHA-256 hashes on their Web sites, as another means of getting a known value of the hash to compare at runtime.

If you determine that getSignatureHash() does not return the right value, this means that the app that is installed on the device is written by somebody other than the app’s original author. Often times, this will mean the app has malware in it. It is up to you to determine how you wish to respond to this scenario:

Examining Public Keys

Under the covers, SignatureUtils uses PackageManager and related classes to examine what they somewhat erroneously refer to as “signatures”. The MiscSecurity/SigDump sample project will allow us to browse the list of installed packages, see a decoded public key on the screen for a package that we select, plus dump the “signature” as a binary file for later comparison using another app.

The UI Structure

In this sample, we use a SlidingPaneLayout for a master-detail pattern presentation, as was demonstrated in the chapter on dealing with multiple screen sizes. The “master” fragment will be the list of packages; the “detail” fragment will be the decoded public key for the selected package.

The master fragment is implemented as PackagesFragment. It implements a typical ListFragment for use with the master/detail pattern, utilizing the activated state to show the context for the detail fragment. The detail will be SignatureFragment, which will display portions of the decoded public key in a TableLayout:

<?xml version="1.0" encoding="utf-8"?>
<TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:shrinkColumns="1"
  android:stretchColumns="1">

  <TableRow>

    <TextView
      android:layout_gravity="center"
      android:layout_margin="4dp"
      android:text="@string/subject"
      android:textStyle="bold"/>

    <TextView android:id="@+id/subject"/>
  </TableRow>

  <TableRow>

    <TextView
      android:layout_gravity="center"
      android:layout_margin="4dp"
      android:text="@string/issuer"
      android:textStyle="bold"/>

    <TextView android:id="@+id/issuer"/>
  </TableRow>

  <TableRow>

    <TextView
      android:layout_gravity="center"
      android:layout_margin="4dp"
      android:text="@string/valid_between"
      android:textStyle="bold"/>

    <TextView android:id="@+id/valid"/>
  </TableRow>

</TableLayout>

Listing the Packages

Our PackagesFragment needs the list of packages to display. It expects the hosting activity to supply that, by using the contract pattern, and having a getPackageList() method on its Contract:

  interface Contract {
    void onPackageSelected(PackageInfo pkgInfo);

    List<PackageInfo> getPackageList();
  }

The hosting activity — MainActivity — retrieves a PackageManager instance in onCreate(), caching it in a mgr data member. getPackageList() then calls getInstalledPackages() on PackageManager, specifically requesting to retrieve signature information via the GET_SIGNATURES flag. The list we get back from getInstalledPackages() can be in any order, so we sort the results before returning it for display purposes:

  @Override
  public List<PackageInfo> getPackageList() {
    List<PackageInfo> result=
        mgr.getInstalledPackages(PackageManager.GET_SIGNATURES);

    Collections.sort(result, new Comparator<PackageInfo>() {
      @Override
      public int compare(final PackageInfo a, final PackageInfo b) {
        return(a.packageName.compareTo(b.packageName));
      }
    });

    return(result);
  }

Note that this is a List of PackageInfo objects, so we need an ArrayAdapter subclass to handle rendering that. Here, we have a PackageListAdapter that knows how to populate list rows using the packageName field of a PackageInfo object, plus using an activated row layout for API Level 11+ devices:

package com.commonsware.android.signature.dump;

import android.annotation.TargetApi;
import android.content.pm.PackageInfo;
import android.os.Build;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.TextView;

class PackageListAdapter extends ArrayAdapter<PackageInfo> {
  PackageListAdapter(PackagesFragment packagesFragment) {
    super(packagesFragment.getActivity(), getRowResourceId(),
          packagesFragment.getContract().getPackageList());
  }

  @Override
  public View getView(int position, View convertView, ViewGroup parent) {
    View result=super.getView(position, convertView, parent);

    ((TextView)result).setText(getItem(position).packageName);

    return(result);
  }

  @TargetApi(Build.VERSION_CODES.HONEYCOMB)
  private static int getRowResourceId() {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
      return(android.R.layout.simple_list_item_activated_1);
    }

    return(android.R.layout.simple_list_item_1);
  }
}

The result is that our master list is a list of all installed packages, sorted by package name, with the detail TableLayout peeking out of the right edge when shown on a phone-sized screen:

Signature Dump Demo, As Initially Launched
Figure 852: Signature Dump Demo, As Initially Launched

Dumping the Key

onListItemClick() of our PackagesFragment routes control to onPackageSelected() of the Contract interface, which in our case is MainActivity. There, we need to do some useful stuff based upon the fact that the user tapped on a particular package:

  @Override
  public void onPackageSelected(PackageInfo pkgInfo) {
    Signature[] signatures=pkgInfo.signatures;
    byte[] raw=signatures[0].toByteArray();

    sigDisplay.show(raw);
    panes.closePane();

    File output=
        new File(getExternalFilesDir(null),
                 pkgInfo.packageName.replace('.', '_') + ".bin");

    new WriteThread(output, raw).start();
  }

First, we get the Signature array from the PackageInfo object. While this is an array, usually an app will only be signed once. Signing more than once is not especially useful, as an upgraded app needs to match the count and contents of each signature. Hence, we will only pay attention to the first signature. If you are using these techniques as the basis for your client JAR checking the public key of your app for IPC protection purposes, and your app is signed with multiple keys, you will want to check all of those keys.

The public key itself is represented as a byte array in the Signature. onPackageSelected() does two things with this byte array:

Decoding the Key

SignatureFragment is mostly comprised of the show() method that MainActivity uses to pass us the byte array of the “signature” to display:

package com.commonsware.android.signature.dump;

import android.app.Fragment;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import java.io.ByteArrayInputStream;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Locale;

public class SignatureFragment extends Fragment {
  DateFormat fmt=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.US);

  @Override
  public View onCreateView(LayoutInflater inflater,
                           ViewGroup container,
                           Bundle savedInstanceState) {
    return(inflater.inflate(R.layout.sig, container, false));
  }

  void show(byte[] raw) {
    CertificateFactory cf=null;

    try {
      cf=CertificateFactory.getInstance("X509");
    }
    catch (CertificateException e) {
      Log.e(getClass().getSimpleName(),
            "Exception getting CertificateFactory", e);
      return;
    }

    X509Certificate c=null;
    ByteArrayInputStream bin=new ByteArrayInputStream(raw);

    try {
      c=(X509Certificate)cf.generateCertificate(bin);
    }
    catch (CertificateException e) {
      Log.e(getClass().getSimpleName(),
            "Exception getting X509Certificate", e);
      return;
    }

    TextView tv=(TextView)getView().findViewById(R.id.subject);

    tv.setText(c.getSubjectDN().toString());

    tv=(TextView)getView().findViewById(R.id.issuer);
    tv.setText(c.getIssuerDN().toString());

    tv=(TextView)getView().findViewById(R.id.valid);
    tv.setText(fmt.format(c.getNotBefore()) + " to "
        + fmt.format(c.getNotAfter()));
  }
}

That byte array really represents an X509 certificate, serialized to a byte array. show() goes through the work to get the X509Certificate object representing that same data, assuming the byte array is not corrupted somehow. Then, show() populates some TextView widgets in our TableLayout with the:

A debug signing key output will resemble:

Signature Dump Demo, Showing Debug Signing Key
Figure 853: Signature Dump Demo, Showing Debug Signing Key

A self-signed production signing key will resemble:

Signature Dump Demo, Showing Production Signing Key
Figure 854: Signature Dump Demo, Showing Production Signing Key

A signing key created by some signing authority would have a subject that is distinct from its issuer.

Choosing Your Signing Keysize

The preview of this section was stepped on by Godzilla.

Avoiding Accidental APIs

The preview of this section is presently indisposed.

Other Ways to Expose Data

The preview of this section took that left turn at Albuquerque.

Jacking Attacks

The preview of this section is in the process of being translated from its native Klingon.

Using FLAG_SECURE

The preview of this section was eaten by a grue.