The package name serves as a unique identifier for the application.
So basically 2 apk which refer to he same app will have same package name.
Then maybe one of these apk is corrupted somehow eg :
- signature file is missing-inconsistent
- public key file is missing-inconsistent
- computing of digest of files's entries in CERT.SF doesn't match (for one or several files listed)
- CERT.SF file's digest (at the beginning of the file) doesnt't match with computing of its own digest
If you want to be sure that one of this app has not been modified by 3rd part, you will have to do all these check above.
Then to sum up the whole thing of determining if 2 apks are the same official app :
- package name must be the same
- public keys must be the same
- computing of digests of file listed in CERT.SF must match with file entries' digest in the same CERT.SF file
- computing of digest of file CERT.SF must match with CERT.SF's own digest
CERT.SF are not necesserally the same if apk refer to the same app with different version (files added or deleted) but public key/private key pair must remained untouched to enable update of this app (unless it will result in "signature conflict" or "existing package already exist" errors)
Using Java
Check signature verification
You can use JarSigner source code for this : http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/sun/security/tools/JarSigner.java#JarSigner.signatureRelated%28java.lang.String%29
with external jar lib sun-security-tool : http://www.java2s.com/Code/Jar/a/Downloadandroidsunjarsignsupport11jar.htm
Check public keys are the same
Compare the extracted public key. Here is the method I made for extracting PKCS7 certificate and public key from it :
/**
* Retrieve public key from PKCS7 certificate
*
* @param certPath
* @return
* @throws IOException
* @throws InvalidKeySpecException
* @throws NoSuchAlgorithmException
*/
public static String getPublicKey(String certPath) throws IOException, InvalidKeySpecException, NoSuchAlgorithmException {
File f = new File(certPath);
FileInputStream is = new FileInputStream(f);
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
int nRead;
byte[] data = new byte[16384];
while ((nRead = is.read(data, 0, data.length)) != -1) {
buffer.write(data, 0, nRead);
}
buffer.flush();
PKCS7 test = new PKCS7(buffer.toByteArray());
X509Certificate[] certs = test.getCertificates();
for (int i = 0; i < certs.length; i++) {
if (certs[i] != null && certs[i].getPublicKey() != null) {
return new BASE64Encoder().encode(certs[i].getPublicKey().getEncoded());
}
}
return "";
}
Read package-name from Android Manifest
Here you have to parse Android binary XML for extracting these information. with this link, you have a lot of tools you can use (and snippet code) :
How to parse the AndroidManifest.xml file inside an .apk package
To get your app-name this is a bit different, this is an Android compiled resource. apktool can decode that kind of file but if you want to do this in java you'll have to decode it yourself. Here is apktool decoder https://github.com/iBotPeaches/Apktool/blob/master/brut.apktool/apktool-lib/src/main/java/brut/androlib/ApkDecoder.java. But if you want the app name it is not necessary in string.xml so this is rather something specific you want to do.
I have made a Java tool that makes jar verification / public key comparison : https://github.com/bertrandmartel/apk-checker
Using Bash
With command line, you can test your output much faster and easier :
Check signature verification
jarsigner -verbose -verify <your_apk_file_name>.apk | grep "jar verified"
Check public keys are the same
unzip -p <your_apk_file_name1>.apk META-INF/CERT.RSA | keytool -printcert
check package-name are the same
aapt d xmltree <your_apk_file_name1>.apk AndroidManifest.xml | grep "package=" | sed -e "s/.*=//g" | sed -e "s/ .*//g"
A gist for Bash scripts is available at https://gist.github.com/bertrandmartel/374564b950e8a577550b