如何获取APK签名签名?

78

有没有一种方法可以检索签署APK所使用的密钥的签名? 我用密钥库中的密钥对我的APK进行了签名。 如何通过编程方式检索该密钥的签名?


你可以使用一个Ant脚本来签名它。但这将要求你将密码存储在一个不安全的地方。 - clamp
我只需要从我的应用程序中获取签名,例如在我的第一个活动中,我不知道如何获取我的应用程序签名。到目前为止,我还不知道如何做。 - Waypoint
啊,我现在明白了。我不确定这是否可能。 - clamp
3个回答

80
你可以使用PackageManager类来访问APK的签名,代码如下: http://developer.android.com/reference/android/content/pm/PackageManager.html
Signature[] sigs = context.getPackageManager().getPackageInfo(context.getPackageName(), PackageManager.GET_SIGNATURES).signatures;
for (Signature sig : sigs)
{
    Trace.i("MyApp", "Signature hashcode : " + sig.hashCode());
}

我使用这个方法与我的调试密钥的哈希码进行比较,以确定APK是调试版还是发布版。


14
有没有办法获取一个未安装应用程序的签名?比如说我有一个.apk文件。 - Ruzard
5
此方法不具备抗碰撞能力。 - thejh
3
对于严重的情况,不要使用hashCode()。例如,如果您想验证您要通信的某个其他应用程序是否使用正确的密钥进行签名,请使用具有密码学安全性的哈希函数(例如SHA256)。 - CommonsWare
2
@Ruzard 是的,你可以这样做。你需要将未安装的apk推送到程序可以获取apk的位置,例如SD_CARD,然后使用context.getPackageManager().getPackageAchiveInfo(NOT_INSTALL_APK_PATH,PackageManager.GET_SIGNATURES) .signatures[0]来获取它的hashCode,并进行比较。祝你好运! - Shengfeng Li
3
@HosseinShahdoost 是的,他们已经覆盖了它,但仍不安全可用。计算得出的哈希值只有32位,很容易发生碰撞。有关详细信息,请参见https://stackoverflow.com/a/60415924。 - Fabian Meumertzheim
显示剩余10条评论

33

软件包管理器将为任何已安装的软件包提供签名证书。然后,您可以打印出签名密钥的详细信息,例如:

final PackageManager packageManager = context.getPackageManager();
final List<PackageInfo> packageList = packageManager.getInstalledPackages(PackageManager.GET_SIGNATURES);

for (PackageInfo p : packageList) {
    final String strName = p.applicationInfo.loadLabel(packageManager).toString();
    final String strVendor = p.packageName;

    sb.append("<br>" + strName + " / " + strVendor + "<br>");

    final Signature[] arrSignatures = p.signatures;
    for (final Signature sig : arrSignatures) {
        /*
        * Get the X.509 certificate.
        */
        final byte[] rawCert = sig.toByteArray();
        InputStream certStream = new ByteArrayInputStream(rawCert);

        try {
            CertificateFactory certFactory = CertificateFactory.getInstance("X509");
            X509Certificate x509Cert = (X509Certificate) certFactory.generateCertificate(certStream);

            sb.append("Certificate subject: " + x509Cert.getSubjectDN() + "<br>");
            sb.append("Certificate issuer: " + x509Cert.getIssuerDN() + "<br>");
            sb.append("Certificate serial number: " + x509Cert.getSerialNumber() + "<br>");
            sb.append("<br>");
        }
        catch (CertificateException e) {
            // e.printStackTrace();
        }
    }
}

验证具有相应序列号的文件的命令是什么:unzip -p [path_to_apk] META-INF/CERT.RSA | keytool -printcert - JY2k

8
我的情况是,我有一个预安装的apk使用了错误的密钥库。因此直接安装会失败,因为签名不一致。我需要先检查签名,以确保可以顺利安装。
这是我的解决方案。
正如此代码所述,您可以从已安装的apk获取签名。
详情:
Signature sig = context.getPackageManager().getPackageInfo(context.getPackageName(), PackageManager.GET_SIGNATURES).signatures[0];

其次:获取releaseApk的哈希码进行比较。在我的情况下,我从服务器下载了这个apk,并将其放在sd_card中。
Signature releaseSig = context.getPackageManager().getPackageArchiveInfo("/mnt/sdcard/myReleaseApk.apk", PackageManager.GET_SIGNATURES).signatures[0];

最后,比较hashCode。
return sig.hashCode() == releaseSig.hashCode;

我已经尝试了上面的代码,它完全正常。如果hashCode不同,您应该只需要卸载旧的apk,或者如果它是系统应用程序并且设备已经root,您可以使用runtime来删除它,然后安装新的签名apk。

1
获取包归档信息,而不是获取包归档信息。 - frogoscar
1
如果应用程序的目标为Android >= 11,则需要特殊权限。https://dev59.com/elIG5IYBdhLWcg3w5GEu - NitZRobotKoder

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接