This page outlines how to verify that the APK or APEX installed on your Android device corresponds to the claims made in the Claimant Model. The process involves pulling the APK from your device and performing a log inclusion proof on the extracted artifact.
Verification Process
A transparency log is implemented with a Merkle tree consisting of hashes. A leaf node contains data, and a parent node contains the hash of its children.
Two fundamental computations verify the tamper-evident property of transparency logs: the inclusion proof and the consistency proof. The inclusion proof confirms that the log includes an entry for a specific APK version. This log entry contains a hash, which is the SHA256 digest of the APK file that is installed on the device. The consistency proof ensures that when new entries are added, the new checkpoint remains cryptographically consistent with previous versions of the tree (or that the tree has not been tampered with). We focus on the process of computing inclusion proof in this guide, while relying on witnesses to continuously perform consistency proof against latest checkpoints.
To verify a covered APK, perform an inclusion proof against a witnessed checkpoint. Note that we plan to integrate this log with a public witness network using a standardized witness protocol. This integration will provide witnessed checkpoints, guaranteeing the consistency of the log.
To verify that the Google apps on your device conform to the claims made in the claimant model, follow the steps below.
Inclusion Proof
You can verify that a covered APK on your device is in the log by extracting the APK, calculating its hash, and using an inclusion proof to check if that hash exists in the published checkpoint. A successful inclusion proof provides assurance against the risks described in the Threat Model, confirming the app is a legitimate Google app.
How to Verify an APK Inclusion In Log
Any app claiming to be a 1st party Google app can be verified against this log.
Prerequisites to Verifying
Before verifying an extracted APK, the following tools should be installed on your computer:
Android Debug Bridge (ADB)
ADB is a tool that communicates with an Android device, available on the
Android SDK Platform Tools website.
AAPT2
AAPT2 (Android Asset Packaging Tool) is a build tool used to compile and
package an Android app's resources.
It is available as a standalone tool in Android SDK Build Tools 26.0.2 and
higher.
Golang
The verification tool is written in Go. To build it, install Go 1.17 or later from the Go site.
Inclusion Proof verifier
We publish a Go module named verifier in the
android-binary-transparency GitHub repository.
This tool queries the Google 1st Party APK transparency log to check if a
package is included.
To use this tool, first clone the repository to your local computer:
git clone https://github.com/android/android-binary-transparency
The source code for the verifier can be found within the
android-binary-transparency repository.
Construct a Payload for Verification
To verify your extracted APK, you must construct a log payload using information derived from the APK itself.
Before you begin, enable USB debugging on your device to allow adb
connections.
Next, locate the installed APK on your device. This guide uses the
Google Play services APK (com.google.android.gms) as a working example.
adb shell pm path com.google.android.gms
You should see output similar to the following:
computer:~$ adb shell pm path com.google.android.gms
package:/data/app/~~oI3N-m7I3VNMk5eKUCscQg==/com.google.android.gms-O79jYXgqkqKaQ9IzJ5zqfA==/base.apk
package:/data/app/~~oI3N-m7I3VNMk5eKUCscQg==/com.google.android.gms-O79jYXgqkqKaQ9IzJ5zqfA==/split_CronetDynamite_installtime.apk
package:/data/app/~~oI3N-m7I3VNMk5eKUCscQg==/com.google.android.gms-O79jYXgqkqKaQ9IzJ5zqfA==/split_DynamiteLoader_installtime.apk
package:/data/app/~~oI3N-m7I3VNMk5eKUCscQg==/com.google.android.gms-O79jYXgqkqKaQ9IzJ5zqfA==/split_DynamiteModulesA_installtime.apk
package:/data/app/~~oI3N-m7I3VNMk5eKUCscQg==/com.google.android.gms-O79jYXgqkqKaQ9IzJ5zqfA==/split_DynamiteModulesC_installtime.apk
package:/data/app/~~oI3N-m7I3VNMk5eKUCscQg==/com.google.android.gms-O79jYXgqkqKaQ9IzJ5zqfA==/split_GoogleCertificates_installtime.apk
package:/data/app/~~oI3N-m7I3VNMk5eKUCscQg==/com.google.android.gms-O79jYXgqkqKaQ9IzJ5zqfA==/split_MapsDynamite_installtime.apk
package:/data/app/~~oI3N-m7I3VNMk5eKUCscQg==/com.google.android.gms-O79jYXgqkqKaQ9IzJ5zqfA==/split_MeasurementDynamite_installtime.apk
package:/data/app/~~oI3N-m7I3VNMk5eKUCscQg==/com.google.android.gms-O79jYXgqkqKaQ9IzJ5zqfA==/split_config.en.apk
package:/data/app/~~oI3N-m7I3VNMk5eKUCscQg==/com.google.android.gms-O79jYXgqkqKaQ9IzJ5zqfA==/split_config.xxhdpi.apk
package:/data/app/~~oI3N-m7I3VNMk5eKUCscQg==/com.google.android.gms-O79jYXgqkqKaQ9IzJ5zqfA==/split_maps_core_dynamite_ondemand.apk
This output indicates that one base APK and several split APKs are installed
for com.google.android.gms on your device.
The exact number of split APKs varies depending on your device's configuration.
Each split APK shares the same package name and version code as the base APK.
Download the listed APKs from your Android device to your computer using the following command (noting that your actual file paths may vary):
mkdir -p /tmp/testdir/gms && cd /tmp/testdir/gms && \
adb shell pm path com.google.android.gms | cut -d':' -f2 | tr -d '\r' | xargs -n1 adb pull
To verify the package name and version of the downloaded APKs, you need to
inspect their manifest (AndroidManifest.xml).
Because the manifest inside an APK is in a binary format, use the aapt2 tool
(installed during the prerequisites step) to extract and read the
information directly from the APK:
computer:/tmp/testdir/gms$ aapt2 dump badging ./base.apk
package: name='com.google.android.gms' versionCode='260834035' versionName='26.08.34 (260400-876566425)' platformBuildVersionName='Baklava' platformBuildVersionCode='36' compileSdkVersion='36' compileSdkVersionCodename='Baklava'
minSdkVersion:'35'
targetSdkVersion:'36'
...
You should repeat this step to get the relevant information until you have accounted for all the split APKs installed on your device.
The output confirms the APK's package name is com.google.android.gms and its
version number (versionCode) is 260834035.
Next, compute the cryptographic hash of each APK:
computer:/tmp/testdir/gms$ sha256sum *.apk
66aa2d7b9752cdd61065b55c8e16739d8367fa18a0f1c8c84122369f86958f1a base.apk
c20754aee886cc55a9de91ee15c623c59d94ad22b7e435a1a48afc43cf1a106c split_config.en.apk
68c09b63a1262e0d34020c139bc77deff3c32bd2b01177abac64790a62fb3be6 split_config.xxhdpi.apk
cd746820c27babd855fa5daea6fabcdf7b44abf3060bc547adc4219212410af0 split_CronetDynamite_installtime.apk
512ee48b60fdb0787a17f84a7dc448fdbf885b2b86a9cb50525d4c22d561b0f1 split_DynamiteLoader_installtime.apk
9e0c74bdc75c50c80d4e2e580a7eda6b8391423ab1161645f41ec6cadc07d678 split_DynamiteModulesA_installtime.apk
955780ac01f59b98bd9be12968f3824ad71b762620f7bf223c569c1a6ab7056c split_DynamiteModulesC_installtime.apk
34c4a2e32d31554d55fc1519e2cfc3ed5027a090fb29b54cfc99f42d1da43bc5 split_GoogleCertificates_installtime.apk
475e18dde92472cde9d8300c082b6dc269613db03398bcd9d1987dff3e68f7b5 split_maps_core_dynamite_ondemand.apk
f83faf40f08bc13f4879302e01c08c863ca2304b4b4e7c9eaf8cd1e869bb6573 split_MapsDynamite_installtime.apk
ec6d854ddda6cd1ba2ba7af2d9fdf4f28c5c78be8713c64521c785429296738c split_MeasurementDynamite_installtime.apk
You now have all the information required to construct a log payload, formatted as described in the Log Content section. Selecting one hash from the results as an example (you should verify the hash of every split APK), the log payload looks like this:
66aa2d7b9752cdd61065b55c8e16739d8367fa18a0f1c8c84122369f86958f1a
SHA256(APK)
com.google.android.gms
260834035
Ensure you include a newline character at the end of the file. Save this content
to a file, such as payload.txt, to use with the verifier tool later.
Verifying Package Inclusion (Inclusion Proof)
With your payload constructed, you can now check if the package is included in
the transparency log. Build the inclusion proof tool from the
android-binary-transparency repository you cloned earlier:
go build cmd/verifier/verifier.go
This should result in an executable named verifier in that directory.
Run the verifier, providing the path to your payload and specifying the log type:
computer:android-binary-transparency$ PAYLOAD_PATH=PATH_TO_PAYLOAD_DIR/payload.txt
computer:android-binary-transparency$ ./verifier --payload_path=${PAYLOAD_PATH} --log_type=google_1p_apk
The verifier uses the checkpoint and log contents (from the tile directory) to check if your APK payload is in the transparency log, confirming it was published by Google.
The command outputs to stderr:
OK. inclusion check success!if the package is included in the log.FAILUREif it is not.
Auto Verifying All Packages In A Device
Given the number of Google apps that may be pre-installed on your device, enumerating each app and performing inclusion proofs individually can be tedious.
We provide another automated tool called Uraniborg that can detect and measure
all currently installed packages on your device.
It feeds its output directly into the verifier tool,
allowing you to discover and verify the transparency of all apps on your
device in a single step.
To use this automated workflow, ensure your Android device is connected to your
computer via ADB. The Uraniborg source code is also included in the
android-binary-transparency repository.
Run the automate_observation.py script located in the scripts/python directory:
python3 automate_observation.py --pull-all-apks --perform_inclusion_proof_check --verifier_path <path_to_verifier_executable>
When the script completes, you should see output similar to this:
INFO:automate_observation.py:main(858): SUCCESS! Hubble was successfully deployed and executed on connected device ABCDEFGHN01234.
INFO:automate_observation.py:main(860): Hubble output files can be found at: /Users/user/home/src/android-binary-transparency/uraniborg/scripts/python/results/google/lynx/lynx:16/BP4A.260105.004.E1/14587043:user/release-keys/001
Navigate to the output directory indicated by the script.
Inside, locate the file named packages_with_inclusion_proof_signal.txt.
This file lists each installed package alongside an
inclusion_proof_verified field set to either true or false.
A true value indicates that the package has been cryptographically verified
against the transparency log, confirming it complies
with the log's claims.