Android compare signature of current package with debug.keystore

Like everything we do, I have an application that signs debug.keystore (by default) when it is in development mode (build). When this happens, we sign it using our private key. Is there a way to determine at runtime that the current package is signed with debug.keystore (in development mode) or signed with our private key (in production mode).

I tried something like

PackageManager packageManager = getPackageManager(); try { Signature[] signs = packageManager.getPackageInfo(getPackageName(), PackageManager.GET_SIGNATURES).signatures; for (Signature signature : signs) { Log.d(TAG, "sign = " + signature.toCharsString()); } } catch (NameNotFoundException e) { e.printStackTrace(); } 

I do not know what to do next? Is it correct? How to get debug.keystore comparable signature?

I know that there is an MD5 keytool -list -keystore ~/.android/debug.keystore , but there is no "md5 fingerprint" method in the Signature class. I want to do this because of MapView Key, Logging, LicenseChecker etc.

+13
android signature apk
May 25 '11 at 9:42
source share
2 answers

The signature in PackageInfo does not seem to have a name, as this field does not contain the package signature, but the X509 Subscriber Certificate Chain. Note that (most of the time) this chain is apparently limited to one self-signed certificate.

According to the Android developer page, signing your applications a debug certificate certificate is created using this DN: CN=Android Debug,O=Android,C=US

Therefore, it is easy to check whether the application has been signed in debug mode:

 private static final X500Principal DEBUG_DN = new X500Principal("CN=Android Debug,O=Android,C=US"); /* ... */ Signature raw = packageManager.getPackageInfo(getPackageName(), PackageManager.GET_SIGNATURES).signatures[0]; CertificateFactory cf = CertificateFactory.getInstance("X.509"); X509Certificate cert = (X509Certificate) cf.generateCertificate(new ByteArrayInputStream(raw.toByteArray())); boolean debug = cert.getSubjectX500Principal().equals(DEBUG_DN); 
+15
Jun 01 2018-11-11T00:
source share

Based on Jcs answer, we use this to find out at runtime which the running package created:

 private enum BuildSigner { unknown, Joe, Carl, Linda } private BuildSigner whoBuiltThis() { try { PackageManager packageManager = getPackageManager(); PackageInfo info = packageManager.getPackageInfo(getPackageName(), PackageManager.GET_SIGNATURES); Signature[] signs = info.signatures; CertificateFactory cf = CertificateFactory.getInstance("X.509"); X509Certificate cert = (X509Certificate)cf.generateCertificate( new ByteArrayInputStream(signs[0].toByteArray())); PublicKey key = cert.getPublicKey(); int modulusHash = ((RSAPublicKey)key).getModulus().hashCode(); switch (modulusHash) { case 123456789: return BuildSigner.Joe; case 424242424: return BuildSigner.Carl; case -975318462: return BuildSigner.Linda; } } catch (Exception e) { } return BuildSigner.unknown; } 

For any certificate involved, you just need to find the hash once and add it to the list.

The simplest way to โ€œfind the hash onceโ€ might be to simply add a pop-up toast before the switch statement that displays modulusHash , compile your application, run it, write the hash, delete the toast code and add the hash to the list.

Alternatively, when I did this, I created a small template application with one action and one TextView with the identifier tv in the main layout, putting it in the action:

 @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); int hash = 0; try{ PackageManager packageManager = getPackageManager(); PackageInfo info = packageManager.getPackageInfo( "com.stackexchange.marvin", PackageManager.GET_SIGNATURES); Signature[] signs = info.signatures; CertificateFactory cf = CertificateFactory.getInstance("X.509"); X509Certificate cert = (X509Certificate) cf.generateCertificate( new ByteArrayInputStream(signs[0].toByteArray())); PublicKey key = cert.getPublicKey(); hash = ((RSAPublicKey) key).getModulus().hashCode(); }catch(Exception e){} TextView tv = ((TextView)findViewById(R.id.tv)); tv.setText("The Stack Exchange app signature hash is " + hash + "."); tv.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 24); } 

(change com.stackexchange.marvin to your application name), compiled this gadget and sent the APK to all participating developers, asking them to run it on their device and tell me the displayed hash.

+3
Jul 16 '13 at 6:12
source share



All Articles