3

如何检查我的应用程序的签名是否与我用来签署它的证书的签名相匹配?

这就是我应该能够获得证书指纹的方式:

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();
    }

这就是我应该能够获得证书指纹的方式:

keytool -v -list -keystore filenameandpath

我的问题是,这两个给出不同的结果。有人能指出我在搞砸什么吗?

4

4 回答 4

7

您正在计算错误数据的 MD5 哈希。证书的指纹是原始证书的哈希值(MD5、SHA1、SHA256 等)。即,您应该计算这些字节的哈希值:

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

例如,以下计算 SHA1 指纹,如果您愿意,只需将 SHA1 更改为 MD5。

    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;
}
于 2013-07-09T15:58:13.620 回答
1

您可以将 apk 作为 zip 文件打开,然后从 META-INF/CERT.RSA 的二进制内容中过滤 ascii 文本,并检查是否是您唱了它。


尝试:

final void  initVerify(Certificate certificate)

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

于 2013-07-09T13:04:11.533 回答
0

使用您的代码在“测试”模式下收集设备上的指纹——这意味着您有临时代码将该指纹发送到日志(或其他地方)。请务必使用您的生产签名密钥进行测试,而不是调试密钥!

从设备的角度了解后,您可以删除临时代码,并在其他地方与您之前确定的关键代码进行比较。

请注意,尽管您这样做可能是为了防止有人修改您的应用程序并使用另一个密钥对其进行重新签名,但有能力这样做的人也有能力修改您的密钥检查。这是一个可以通过额外的混淆来解决的问题,但您需要提出自己的解决方案,以最大限度地减少攻击者知道要寻找什么的机会。

于 2013-07-09T13:03:21.610 回答
0

下面的代码:

 c.getPublicKey().getEncoded()

应该是这样的

 c.getEncoded()

我认为通过 keytool 检查 md5 是检查 certfile,而不是 publickey

于 2014-06-20T08:09:28.017 回答