Get package signatures:
private static List<String> getSignatures(@NonNull PackageManager pm, @NonNull String packageName) {
try {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
PackageInfo packageInfo = pm.getPackageInfo(packageName, PackageManager.GET_SIGNING_CERTIFICATES);
if (packageInfo == null
|| packageInfo.signingInfo == null) {
return null;
}
if(packageInfo.signingInfo.hasMultipleSigners()){
return signatureDigest(packageInfo.signingInfo.getApkContentsSigners());
}
else{
return signatureDigest(packageInfo.signingInfo.getSigningCertificateHistory());
}
}
else {
@SuppressLint("PackageManagerGetSignatures")
PackageInfo packageInfo = pm.getPackageInfo(packageName, PackageManager.GET_SIGNATURES);
if (packageInfo == null
|| packageInfo.signatures == null
|| packageInfo.signatures.length == 0
|| packageInfo.signatures[0] == null) {
return null;
}
return signatureDigest(packageInfo.signatures);
}
} catch (PackageManager.NameNotFoundException e) {
return null;
}
}
Convert signatures to list of hex strings:
private static String signatureDigest(Signature sig) {
byte[] signature = sig.toByteArray();
try {
MessageDigest md = MessageDigest.getInstance("SHA1");
byte[] digest = md.digest(signature);
return BaseEncoding.base16().lowerCase().encode(digest);
} catch (NoSuchAlgorithmException e) {
return null;
}
}
private static List<String> signatureDigest(Signature[] sigList) {
List<String> signaturesList= new ArrayList<>();
for (Signature signature: sigList) {
if(signature!=null) {
signaturesList.add(signatureDigest(signature));
}
}
return signturesList;
}
Compare package signatures with your whitelist:
private static boolean verifyAppSignature(Context context) {
//you should load approvedSignatures from a secure place not plain text
List<String> approvedSignatures = new ArrayList<>();
approvedSignatures.add("Your whitelist #1");
approvedSignatures.add("Your whitelist #2");
List<String> currentSignatures = getSignatures(context.getPackageManager(), context.getPackageName());
if(currentSignatures!=null && currentSignatures.size()>0) {
//first checking if no unapproved signatures exist
for (String signatureHex : currentSignatures) {
if (!approvedSignatures.contains(signatureHex)) {
return false;
}
}
//now checking if any of approved signatures exist
for (String signatureHex : currentSignatures) {
if (approvedSignatures.contains(signatureHex)) {
return true;
}
}
}
return false;
}