Android APK签名

81 阅读6分钟

Android APK安装时的签名校验原理

Android APK安装时的签名校验原理主要是通过验证APK文件的签名信息来确保APK文件的完整性和来源的可信性。具体过程如下:

  1. 签名生成:开发者使用Android SDK提供的工具生成一个密钥库文件(.keystore),其中包含一个或多个数字证书。然后,使用这些工具将APK文件与数字证书进行关联,生成一个签名文件(如.RSA文件)。

  2. 签名打包:签名文件与APK文件一起打包成最终的APK文件,供用户下载和安装。

  3. 安装时校验:当用户尝试安装APK文件时,Android系统会执行以下校验步骤:

    • 提取签名信息:从APK文件中提取出签名文件(如.RSA文件)和证书信息。
    • 计算摘要:使用与签名时相同的哈希算法(如SHA-256)对APK文件的内容进行哈希计算,得到一个新的摘要。
    • 验证签名:使用证书中的公钥对签名文件中的签名进行解密,得到原始的摘要。然后,将这个解密得到的摘要与刚刚计算出的新摘要进行比较。
    • 检查证书链:验证证书链的有效性,确保证书是由受信任的证书颁发机构(CA)签发的,或者证书链中的某个证书已经预置在Android系统中。
  4. 结果判断:如果签名信息一致且证书链有效,Android系统会认为APK文件是完整且来自可信的开发者,允许用户安装和运行该APK文件。如果签名信息不一致或证书链无效,Android系统会提示用户安装失败或存在潜在风险。

V1到V4签名的异同和特点

签名版本引入时间签名方式安全性兼容性特点
V1 (JAR签名)早期Android版本基于Java签名框架较低广泛- 将整个APK文件作为一个整体进行签名。
- 使用MD5和SHA1哈希算法,以及RSA或DSA加密算法。
- 适用于所有Android系统版本,但安全性较低。
V2 (APK Signature Scheme v2)Android 7.0 (API 24)增量签名较高Android 7.0及以上- 只对APK内容的部分进行签名,提高签名效率和验证性能。
- 使用SHA256哈希算法和ECDSA签名算法。
- 提供对APK文件进行验证和完整性检查的机制。
- 与V1签名共存,确保兼容性。
V3 (APK Signature Scheme v3)Android 9.0 (API 28)进一步增强V2签名更高Android 9.0及以上- 采用更强大的签名算法和更长的密钥长度。
- 仍然采用增量签名方式。
- 提供签名块的完整性保护和签名的附加时间戳。
- 可选使用,应用可同时包含V1、V2和V3签名。
V3.1 (APK Signature Scheme v3+)Android 13V3签名的改进版本更高Android 13及以上- 解决V3签名在轮替方面的一些已知问题。
- 支持SDK版本定位功能,允许轮替定位到平台的更高版本。
- 使用在Android 12或更低版本中无法识别的分块ID。
V4 (APK Signature Scheme v4+)Android 11.0支持ADB增量APK安装特定场景Android 11及以上- 基于Merkle哈希树计算APK的所有字节。
- 完全遵循fs-verity哈希树的结构。
- 签名存储在单独的.apk.idsig文件中,不包含在APK文件中。
- 需要V2或V3签名作为补充,用于ADB增量安装。

总结

Android APK签名是确保APK文件的完整性和来源可信的重要机制。签名过程使用开发者的私钥对APK进行签名,而用户设备上的系统会使用开发者的公钥来验证签名的有效性。结合这篇文章的内容,我们可以从原理和源码层面(特别是PackageManagerService,简称PMS)来详细说明APK签名的过程。


APK签名原理

  1. 签名的目的

    • 完整性:确保APK在传输或存储过程中未被篡改。
    • 来源可信:确保APK来自特定的开发者,且未被第三方冒充。
    • 防止篡改:如果APK被修改,签名会失效,系统会拒绝安装或运行。
  2. 签名过程

    • 开发者使用私钥对APK的摘要(如SHA-256)进行加密,生成签名。
    • 签名和开发者的公钥证书会被打包到APK的META-INF目录中。
    • 安装时,系统会使用公钥验证签名的有效性,并检查APK的完整性。
  3. 签名验证流程

    • 系统提取APK中的签名文件和公钥证书。
    • 使用公钥解密签名,得到APK的摘要。
    • 重新计算APK的摘要,并与解密后的摘要对比,验证是否一致。

结合PMS源码分析签名验证

PackageManagerService(PMS)是Android系统中负责APK安装、卸载和管理的核心服务。签名验证的逻辑主要在PMS中实现。以下是源码中的关键点:

1. 签名验证入口

在PMS中,APK的签名验证主要在PackageParserPackageManagerService中完成。以下是关键方法:

// frameworks/base/core/java/android/content/pm/PackageParser.java
public class PackageParser {
    public static class Package {
        // APK的签名信息
        public Signature[] signatures;
    }

    // 解析APK并验证签名
    public Package parsePackage(File packageFile, int flags) {
        // 解析APK文件
        Package pkg = parsePackage(packageFile, flags);
        // 验证签名
        verifySignatures(pkg);
        return pkg;
    }

    private void verifySignatures(Package pkg) {
        // 获取APK的签名信息
        Signature[] signatures = pkg.signatures;
        if (signatures == null || signatures.length == 0) {
            throw new PackageManagerException("APK has no signatures");
        }
        // 验证签名的有效性
        for (Signature signature : signatures) {
            if (!signature.verify()) {
                throw new PackageManagerException("Signature verification failed");
            }
        }
    }
}

2. PMS中的安装流程

在PMS中,APK的安装流程会调用PackageParser来解析APK并验证签名:

// frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
public class PackageManagerService extends IPackageManager.Stub {
    public void installPackage(String packageName, int flags) {
        // 解析APK
        PackageParser.Package pkg = mPackageParser.parsePackage(packageFile, flags);
        // 验证签名
        verifySignatures(pkg);
        // 继续安装流程
        installPackageTracedLI(pkg);
    }

    private void verifySignatures(PackageParser.Package pkg) {
        // 获取APK的签名信息
        Signature[] signatures = pkg.mSignatures;
        if (signatures == null || signatures.length == 0) {
            throw new PackageManagerException("APK has no signatures");
        }
        // 验证签名的有效性
        for (Signature signature : signatures) {
            if (!signature.verify()) {
                throw new PackageManagerException("Signature verification failed");
            }
        }
    }
}

3. 签名验证的核心逻辑

签名的验证逻辑主要在Signature类中实现:

// frameworks/base/core/java/android/content/pm/Signature.java
public class Signature {
    private final byte[] mSignature;

    public Signature(byte[] signature) {
        this.mSignature = signature;
    }

    // 验证签名的有效性
    public boolean verify() {
        // 使用公钥解密签名
        PublicKey publicKey = getPublicKey();
        try {
            Signature signature = Signature.getInstance("SHA256withRSA");
            signature.initVerify(publicKey);
            signature.update(mSignature);
            return signature.verify(mSignature);
        } catch (Exception e) {
            return false;
        }
    }

    private PublicKey getPublicKey() {
        // 从证书中提取公钥
        CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
        X509Certificate cert = (X509Certificate) certFactory.generateCertificate(new ByteArrayInputStream(mSignature));
        return cert.getPublicKey();
    }
}

APK签名验证的完整流程

  1. 解析APK

    • PMS通过PackageParser解析APK文件,提取签名信息。
  2. 验证签名

    • 使用开发者的公钥解密签名,得到APK的摘要。
    • 重新计算APK的摘要,并与解密后的摘要对比。
  3. 安装APK

    • 如果签名验证通过,PMS会继续安装流程;否则,抛出异常并拒绝安装。

总结

  • APK签名是Android安全机制的核心部分,确保APK的完整性和来源可信。
  • PMS是Android系统中负责APK安装和管理的核心服务,签名验证的逻辑主要在PMS和PackageParser中实现。
  • 通过源码分析,我们可以看到PMS如何解析APK、提取签名信息,并使用公钥验证签名的有效性。

通过结合源码和原理,我们可以更深入地理解Android APK签名的工作机制。