How to verify that app was signed by my certificat

2019-03-17 01:34发布

问题:

How do I check if the signature of my app matches the signature of the certificate that I used to sign it?

This is how I should be able to get the certificates fingerprint:

public String getCertificateFingerprint() throws NameNotFoundException, CertificateException, NoSuchAlgorithmException {
        PackageManager pm = context.getPackageManager();
        String packageName =context.getPackageName();

        int flags = PackageManager.GET_SIGNATURES;

        PackageInfo packageInfo = null;

        packageInfo = pm.getPackageInfo(packageName, flags);
        Signature[] signatures = packageInfo.signatures;

        byte[] cert = signatures[0].toByteArray();

        InputStream input = new ByteArrayInputStream(cert);

        CertificateFactory cf = null;
        cf = CertificateFactory.getInstance("X509");

        X509Certificate c = null;
        c = (X509Certificate) cf.generateCertificate(input);

        MessageDigest md = MessageDigest.getInstance("MD5");
        byte[] publicKey = md.digest(c.getPublicKey().getEncoded());

        StringBuffer hexString = new StringBuffer();
        for (int i = 0; i < publicKey.length; i++) {
            String appendString = Integer.toHexString(0xFF & publicKey[i]);
            if (appendString.length() == 1)
                hexString.append("0");
            hexString.append(appendString);
        }

        return hexString.toString();
    }

This is how I should be able to get the fingerprint of my certificate:

keytool -v -list -keystore filenameandpath

My problem is, that these two give back different results. Could someone point out what I'm screwing up?

回答1:

You are computing the MD5 hash of the wrong data. The fingerprint of a certificate is a hash (MD5, SHA1, SHA256, etc.) of the raw certificate. I.e., you should be computing the hash of these bytes:

byte[] cert = signatures[0].toByteArray();

E.g., the following computes a SHA1 fingerprint, just change SHA1 to MD5 if you prefer.

    public String computeFingerPrint(final byte[] certRaw) {

    String strResult = "";

    MessageDigest md;
    try {
        md = MessageDigest.getInstance("SHA1");
        md.update(certRaw);
        for (byte b : md.digest()) {
            strAppend = Integer.toString(b & 0xff, 16);
            if (strAppend.length() == 1)
                strResult += "0";
            strResult += strAppend;
        }
        strResult = strResult.toUpperCase(DATA_LOCALE);
    }
    catch (NoSuchAlgorithmException ex) {
        ex.printStackTrace();
    }

    return strResult;
}


回答2:

Use your code for collecting the fingerprint on the device in "test" mode -- meaning you have temporary code to emit that fingerprint to the log (or elsewhere). Be sure to test this using your production signing key, not the debug key!

Once you know from the device's perspective, you can remove the temporary code and elsewhere you can compare to what you've previously determined to be the key.

Be aware though that you're probably doing this to prevent someone from modifying your app and re-signing it with another key, but someone with the ability to do that also has the ability to modify your key checking. This is a problem that can be addressed with additional obfuscation but you'll need to come up with your own solution to minimize the chance of an attacker knowing what to look for.



回答3:

You can open the apk as a zip file and filter the ascii text from the binary content of META-INF/CERT.RSA and check there is it you who singed it.


try:

final void  initVerify(Certificate certificate)

from: http://developer.android.com/reference/java/security/Signature.html



回答4:

the code below:

 c.getPublicKey().getEncoded()

it should be like this

 c.getEncoded()

i think md5 check by keytool is check the certfile,not the publickey