12

Is there some way to retrieve information about the apk signature at runtime?

For example I have the same App signed with 2 different signatures: app-1.apk and app-2.apk and I'd like to be able of differentiate both apk in run time. Is that possible?

My goal is to implement a licensing system using a external server and based on the version code of the application and the signature.

CommonsWare
  • 986,068
  • 189
  • 2,389
  • 2,491
Addev
  • 31,819
  • 51
  • 183
  • 302

2 Answers2

14

You can access apk signature using PackageManager. PackageInfo flag defined in Package Manager return information about the signatures included in the package.

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

http://developer.android.com/reference/android/content/pm/PackageManager.html

codemaster
  • 572
  • 1
  • 6
  • 16
  • 7
    Right, except that what the API calls 'signature' is actually the signing _certificate_. Call `toByteArray()` to get the raw certificate. Additionally, `hashCode()` doesn't buy you much, you need to use `MessageDigest` to calculate the certificate hash value for comparison. – Nikolay Elenkov Dec 31 '11 at 04:16
  • @NikolayElenkov This might be an old post but I needed this code implemented. What is the difference between signing cert and raw cert? When I use your method `toByteArray()` instead of `hashCode()` my `MD5` checksum changes every time I run the `.apk` again whereas just using `hashCode()` keeps it stable unless I recompiled the application. What I want is to identify the keystore used to sign the `.apk`. – Synaero Apr 14 '13 at 23:09
  • 4
    `hashCode()` does not return the MD5 checksum, it's a more or less random value identifying the object at runtime. use `MessageDigest.getInstance("MD5").digest(sigs[0].toByteArray())`. BTW, there is no point in identifying the 'keystore', you need to identify the signing key/certificate. – Nikolay Elenkov Apr 15 '13 at 01:34
  • After some testing I realize what you mean by `hashCode` identifies the Signature object and that what is contained within the signature. However, after looking over the Signature class I am confused by the difference between `toByteArray` and `toCharString` logic tells me that one is in bytes and one is in Chars. Is there a difference between hashing one or the other? Also, it seems that toByteArray changes every runtime whereas toCharString doesn't. Would it be wrong of me to use toCharString instead? Thanks for commenting even after such a long time to help me. :) – Synaero Apr 15 '13 at 03:43
  • 1
    But if we are going to authenticate the web service call base on signature,There is catch any application can see you application signature and use that to hack. – Piyush Feb 12 '16 at 06:32
  • @NikolayElenkov I got a certificate MD5 digest string value something like '8e27389349197d05075c0332531b55a8' using `apksigner`, but how can I compare this with the resulting byte[] value from `messageDigest.digest(sigs[0].toByteArray())`? – Jenix May 29 '20 at 18:49
  • Either convert the byte array to hex string, or the hex string to byte array and then compare. – Nikolay Elenkov May 30 '20 at 04:23
  • for the same apk, does "toByteArray()" always return the same value? – Zahra Jamshidi Apr 09 '21 at 12:18
3

This might be a different approach, but why don't you just implement a custom permission, that is signature based? Then you could use the package manager (or a broadcast) to find out if the permission was granted.

If it is, then both signatures are the same, if not they are different.

Force
  • 6,312
  • 7
  • 54
  • 85