Application Signing and the Android 12 Package Checksum

Julius Uy
Big O(n) Development
5 min readMar 21, 2021

--

In a recent article published by Dave Burke, Android 12 is introducing access to app digests.

Here’s how they described it:

For apps that need to validate the integrity of app packages installed on Android devices, we’re introducing a new API that lets you query the platform directly for the checksum of an installed app. You can choose from several digest algorithms such as SHA256, SHA512, Merkle Root, and others. To request a checksum, call PackageManager.requestChecksums() with an app’s package name, the checksum types you need, the installer certs you trust, and a listener to receive the checksums. The platform returns the matching checksums, either precomputed and provided by the installer app (such as Google Play) or computed by the platform. Results are filtered based on package visibility guidelines, so you’ll need to declare the packages of interest in your manifest.

In the past, certain methods have been made available to verify the legitimacy of an Android Application. The most popular is perhaps the SafetyNet Attestation and Verify Apps API. As anyone might know as well, apart from security being a constant cat and mouse game, SafetyNet makes an assumption that the phone comes with Google Play Services. This adds a layer of complexity of course around phones shipped without it. Back at Rakuten Viki, I see as much as 5% of our users installing our app outside of Google Play. Which means that at most, we’re looking at 5% of our app users without Google Play Services.¹

In Android 12, we are introduced to new way for developers to verify apps without Google Play Services through requestChecksums(). It is however unclear how helpful this could be, as I shall note later.

Application Signing

An app developer is required to sign their app before they upload it to Google Play. The signing key is theoretically unique. Therefore, any external entity who comes in to modify the contents of the app can be identified because they need to use a different signing key to repackage the app. Hence, using this line of code, and verifying it against the backend, one is able to identify the authenticity of the app:

PackageInfo certs = context.getPackageManager().getPackageInfo(context.getPackageName(), PackageManager.GET_SIGNING_CERTIFICATES);

Of course, this is not air tight. the general idea of doing this verification comes in some form very similar to this:

Figure 1 — A typical authenticity verification process using signing certificates

However, attackers can do a MITM attack to intercept payloads or through the use of tools like Frida. With this, it is then possible for the attacker to get the certificate hashes and essentially send the fake payload to the backend, thereby allowing him to proceed through the app undetected.

Of course, a simpler way for an attacker to move forward is to simply decompile the app, remove the backend validation code, and simply proceed to the app. Is it however, unclear to the attacker if there are further verifications down the road. Hence, the former is generally the route to go.

How Application Signing Works

There are currently four levels of signing available in Android. This flowchart shows how the APK verification process works:

Figure 2 — The current algorithm to verify application signature

The most primitive signing method is through JAR signing. Android specific signing begins with v2 through the following illustration:

Figure 3 — Application Signing v2

Introduced in Android 7.0, this signing strategy uses the Merkle Tree. Here’s what it looks like:

Figure 3 — An example of a Merkle Tree

The way the Merkle Tree works is quite simple. As you can see above, the leaf nodes are hashed, and then the hash of that leaf and the one next to it are combined and hashed. The process repeats until one reaches the root, which is the hash of all the nodes, including the leaf.

Merkle Tree interestingly, is an algorithm used in modern blockchain implementations. Git likewise uses the same implementation.

Application Signing V2 follow a very similar strategy:

Figure 4 — Application Signing v2 Merkle tree

Also interestingly, Android common Kernel is using fs-verity, which is a means to put the root digest of the Merkle tree into a readonly file for regular counterchecks.

Later versions of Application Signing simply adds support for key rotation, which is validated through a single directional linked list, with each node containing a signing certificate used to sign previous versions of the app. They now also allow multiple signing certificates. v4 adds streaming support and follows fs-verity Merkle Tree.

The new Android 12 specific functionality now supports this method on PackageManager:

public void requestChecksums (String packageName, 
boolean includeSplits,
int required,
List<Certificate> trustedInstallers,
PackageManager.OnChecksumsReadyListener onChecksumsReadyListener)

Without the need to go into too much detail since the method documentation is already linked above, the idea is for the app developer to use this to check the authenticity of the app, likewise in the absence of Google Play Services.

Practical usage thus follows a very similar pattern as seen in Figure 1 above, apart from the ones I highlighted in orange:

Figure 5 — A typical authenticity verification process using checksums

You might recall that I mentioned that it is unclear how helpful this new method is. For one, decompiling an APK and removing the lines of code performing this check neutralizes the protection this provides. At Viki, around 1% of our overall installs are modified APKs. It is also unclear if the Zip Entry Contents and the Central Directory can be tampered with while maintaining the same package signature. (Theoretically it should not) Hence, I’m still uncertain on the added benefit here. Since the Android Developer blog is intended to be readable by a wide range of audience, the deeper details around the additional protection this method provides is abstracted away. That said, it is still a welcome option nonetheless.

____

¹ The actual number is definitely lower. Likewise, games for example will tend to have higher percentage of installs outside of Google Play. Your mileage may vary.

--

--

Julius Uy
Big O(n) Development

Head of Technoogy at Choo choo Train Singapore. ex-CTO here ex-CTO there. On some days, I'm also a six year old rabbit.