77

Is there a way to retrieve the signature of the key used to sign an APK? I signed my APK with my key from my keystore. How can I retrieve it programmatically?

Yojimbo
  • 23,288
  • 5
  • 44
  • 48
Waypoint
  • 17,283
  • 39
  • 116
  • 170
  • you could use an ant script to sign it. but it will require you to store your passwords somewhere which is unsafe. – clamp Apr 07 '11 at 09:29
  • I just need to get signature from my app inside it, e.g. in my first activity I somehow get my app signature. Up to now I don't know how – Waypoint Apr 07 '11 at 09:41
  • ah i understand now. i am not sure if this is possible. – clamp Apr 07 '11 at 09:43

3 Answers3

80

You can access the APK's signing signature like this using the PackageManager class http://developer.android.com/reference/android/content/pm/PackageManager.html

Signature[] sigs = context.getPackageManager().getPackageInfo(context.getPackageName(), PackageManager.GET_SIGNATURES).signatures;
for (Signature sig : sigs)
{
    Trace.i("MyApp", "Signature hashcode : " + sig.hashCode());
}

I've used this to compare with the hashcode for my debug key, as a way to identify whether the APK is a debug APK or a release APK.

Ollie C
  • 28,313
  • 34
  • 134
  • 217
  • how do you know whether it is signed with debug or release key? I get: 08-08 08:24:36.668: I/Platform(19131): Signature hashcode : -1907392821 I don't even know how to verify whether it is my package or not... (I need to verify whether com.mypackage.myapp belongs to me or not) – Zennichimaro Aug 08 '12 at 08:26
  • 1
    http://stackoverflow.com/questions/6122401/android-compare-signature-of-current-package-with-debug-keystore?rq=1 lets me differentiate between debug or release apk, but is there a way to validate my signature against my public key to verify the apk actually comes from me? Thanks! – Zennichimaro Aug 08 '12 at 08:38
  • 14
    is there a way to get a signature of a not installed application? For example if I have an .apk file – Ruzard Sep 03 '13 at 19:24
  • 5
    this approach is not collision resistant – thejh Oct 29 '14 at 13:24
  • 3
    For serious cases, don't use `hashCode()`. For example, if you want to validate that some other app that you want to communicate with was signed with the right key, use a cryptographically-secure hash (e.g., SHA256). – CommonsWare Aug 20 '15 at 19:18
  • 2
    @Ruzard Yes, you can. You need to push the not installed apk to the location where you program can get the apk such as SD_CARD, then use context.getPackageManager().getPackageAchiveInfo(NOT_INSTALL_APK_PATH,PackageManager.GET_SIGNATURES) .signatures[0] to get its hashCode. and compare them . Good luck – Shengfeng Li Jul 27 '16 at 14:44
  • what does Trace.i() method do..? Somebody please help me understand. – eRaisedToX Jan 20 '17 at 10:41
  • Why is this the accepted answer? .hashCode() just returns the Java Object's has code, which is useless to know in this context. – swooby Feb 23 '18 at 00:18
  • 2
    @CommonsWare shouldn't `hashCode` return the id of the object in memory? – Hossein Shahdoost Apr 04 '18 at 16:26
  • @HosseinShahdoost: Ummm... yes. Which even further means that you shouldn't use `hashCode()` here. :-) – CommonsWare Apr 04 '18 at 16:31
  • @CommonsWare well, I asked a question about this here https://stackoverflow.com/questions/49651834/is-signature-hashcode-referring-to-the-right-hashcode/49657447 and apparently they have overwritten the method `Signature.hashCode()`, it returns the hashCode of the signature not the object in memory – Hossein Shahdoost Apr 05 '18 at 07:54
  • 3
    @HosseinShahdoost Yes, they have overwritten it, but it is still not safe to use. The computed hash consists of 32 bits, which allows for trivial collisions. See https://stackoverflow.com/a/60415924 for details. – Fabian Meumertzheim Feb 26 '20 at 14:21
  • @fhenneke of course, the returned hash shouldn't be used for anything serious but the main problem was that they have decided to override such a fundamental method. I think the whole idea was wrong. – Hossein Shahdoost Mar 03 '20 at 16:10
  • how to get it using deployment_cert.der? – Bhavin Patel Sep 28 '20 at 07:07
  • need special permission if app targets android >=11. https://stackoverflow.com/questions/62345805/namenotfoundexception-when-calling-getpackageinfo-on-android-11 – NitZRobotKoder Aug 26 '21 at 08:30
33

The package manager will give you the signing certificate for any installed package. You can then print out the details of the signing key, e.g.

final PackageManager packageManager = context.getPackageManager();
final List<PackageInfo> packageList = packageManager.getInstalledPackages(PackageManager.GET_SIGNATURES);

for (PackageInfo p : packageList) {
    final String strName = p.applicationInfo.loadLabel(packageManager).toString();
    final String strVendor = p.packageName;

    sb.append("<br>" + strName + " / " + strVendor + "<br>");

    final Signature[] arrSignatures = p.signatures;
    for (final Signature sig : arrSignatures) {
        /*
        * Get the X.509 certificate.
        */
        final byte[] rawCert = sig.toByteArray();
        InputStream certStream = new ByteArrayInputStream(rawCert);

        try {
            CertificateFactory certFactory = CertificateFactory.getInstance("X509");
            X509Certificate x509Cert = (X509Certificate) certFactory.generateCertificate(certStream);

            sb.append("Certificate subject: " + x509Cert.getSubjectDN() + "<br>");
            sb.append("Certificate issuer: " + x509Cert.getIssuerDN() + "<br>");
            sb.append("Certificate serial number: " + x509Cert.getSerialNumber() + "<br>");
            sb.append("<br>");
        }
        catch (CertificateException e) {
            // e.printStackTrace();
        }
    }
}
Yojimbo
  • 23,288
  • 5
  • 44
  • 48
  • What is the command to validate the file with the corresponding serialNumber: unzip -p [path_to_apk] META-INF/CERT.RSA | keytool -printcert – JY2k Jan 02 '17 at 14:40
8

My situation is that I have a pre-installed apk which use a wrong key-store . So directly install will give a fail because of inconsistent signature.I need to check the signature first to make sure it can be install smoothly.

Here is my solution.

As this code says, you can get the signature from an installed apk.

details:

Signature sig = context.getPackageManager().getPackageInfo(context.getPackageName(), PackageManager.GET_SIGNATURES).signatures[0];

Secondly: get the releaseApk hashCode to compare. In my case, I downloaded this apk from my server, and put it in the sd_card.

Signature releaseSig = context.getPackageManager().getPackageArchiveInfo("/mnt/sdcard/myReleaseApk.apk", PackageManager.GET_SIGNATURES).signatures[0];

Finally,compare the hashCode.

return sig.hashCode() == releaseSig.hashCode;

I have tried the code above, it works just fine. If the hashCode is different, you should just uninstall the old apk or if it's a system app and the device is rooted, you can just use runtime to remove it,and then install the new signature apk.

Shengfeng Li
  • 606
  • 7
  • 11