Based on Jcs' answer, we use this to find out at runtime who built the running package:
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 involved certificate, you then just have to find the hash once and add it to the list.
The simplest way to "find the hash once" may be to just add a popup toast before the switch statement that displays modulusHash
, compile your app, run it, write down the hash, remove the toast code and add the hash to the list.
Alternatively, when I implemented this, I created a little boilerplate app with a single activity and a single TextView
with the ID tv
in the main layout, put this into the activity:
@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's signature hash is " + hash + ".");
tv.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 24);
}
(change com.stackexchange.marvin
to your app's name), compiled this mini-app, and sent the APK to all involved developers, asking them to run it on their dev device and let me know the displayed hash.