Android - How can I verify the authenticity of an APK file I downloaded?

Sidestepping the debate over the legitimacy of installing that app on your phone, the question of verification is one that I've been meaning to understand for a while, and you've prompted me to try to figure out a possible way of verifying who signed an apk.

Android apps are signed in the normal manner of .jar files (.apk is really just a special .jar which is just a special .zip) however it may not be trivial to trace the authenticity of the certificates unless you have something known good to compare to. That's basically what the phone itself does - verifies that something that claims to be from the same party as something already on the phone actually is - the phone doesn't refuse to install things with unknown signers, it can only (object to/clear application data of) apparent forgeries when something new doesn't match something old that it claims to.

You will need to have jarsigner and keytool. I believe these come from the JDK which is a prerequisite to the android SDK rather than the SDK itself.

First you want try to verify the public key contained within the .apk. Usually this is in META-INF/CERTS.RSA but it can be in another file - unzip -l will tell you. You want to see what you can find out about it:

unzip -p suspect.apk META-INF/CERT.RSA | keytool -printcert

That's going to dump out a lot of information about who the signer claims to be. Some certificates are apparently themselves signed by known parties, but without figuring out how to trace that, I suspect you could do something like this:

unzip -p suspect.apk META-INF/CERT.RSA | keytool -printcert | grep MD5
unzip -p knowngood.apk META-INF/CERT.RSA | keytool -printcert | grep MD5

If you have a known trusted apk from the same author who used the same certificate. I'm assuming that the certificates having the same MD5 sum is enough.

Assuming you've decided to trust the certificate, then you can see if it has been used to sign each of the files within the .apk

jarsigner -verbose -verify suspect.apk

(If there's more than one .RSA file in the archive, you should add the -certs flag to tell you which certificate(s) have been used to sign each file, so you can be sure its the certificate you verified)


The correct way to verify an APK file is to use apksigner.

apksigner is part of the Android build tools, therefore you may find multiple versions installed, one for each build-tools version installed.

One example path within the Android SDK to apksigner is:

android-sdk/build-tools/29.0.2/apksigner

Execute apksigner this way:

apksigner verify --verbose --print-certs "Signal-website-universal-release-4.49.13.apk"

Verifies
Verified using v1 scheme (JAR signing): true
Verified using v2 scheme (APK Signature Scheme v2): true
Verified using v3 scheme (APK Signature Scheme v3): true
Number of signers: 1
Signer #1 certificate DN: CN=Whisper Systems, OU=Research and Development, O=Whisper Systems, L=Pittsburgh, ST=PA, C=US
Signer #1 certificate SHA-256 digest: 29f34e5f27f211b424bc5bf9d67162c0eafba2da35af35c16416fc446276ba26
Signer #1 certificate SHA-1 digest: 45989dc9ad8728c2aa9a82fa55503e34a8879374
Signer #1 certificate MD5 digest: d90db364e32fa3a7bda4c290fb65e310
Signer #1 key algorithm: RSA
Signer #1 key size (bits): 1024
Signer #1 public key SHA-256 digest: 75336a3cc9edb64202cd77cd4caa6396a9b5fc3c78c58660313c7098ea248a55
Signer #1 public key SHA-1 digest: b46cbed18d6fbbe42045fdb93f5032c943d80266
Signer #1 public key MD5 digest: 0f9c33bbd45db0218c86ac378067538d
<skipped a lot of warnings>

Now you have verified the APK, but you still don't know if you can trust the person/organization who has signed the APK file. This is because on Android APK signatures use by definition self-signed certificates. If you can trust a certificate is therefore a difficult question. The only way is to check the other apps that have been signed using the same certificate.

The only way I know to do so is to use online PlayStore crawling services like androidobservatory.org. It has an API for checking which apps have been signed by the same certificate using the certificate SHA-1 digest:

  • SHA-1: https://androidobservatory.org/cert/45989DC9AD8728C2AA9A82FA55503E34A8879374

Edit: apkmirror.com also allows to search for the certificate digest. Just enter the plain SHA-1 or SHA-256 certificate digest (without colons or spaces) in the search field:

  • SHA-1: https://www.apkmirror.com/?post_type=app_release&searchtype=app&s=45989DC9AD8728C2AA9A82FA55503E34A8879374
  • SHA-256: https://www.apkmirror.com/?post_type=app_release&searchtype=apk&s=29f34e5f27f211b424bc5bf9d67162c0eafba2da35af35c16416fc446276ba26

On this page you can see all the other APK files on Google Play Store that are signed with the same certificate.


There is (now) an apksigner tool in build-tools that does what you want. From the docs:

Check whether the APK's signatures are expected to be confirmed as valid on all Android platforms that the APK supports:

apksigner verify [options] app-name.apk

Tags:

Security

Apk