Android三种签名方式

·  阅读 559

三、加固重签名遇到的问题 先来看一下android 的签名,下面是android签名的官方文档 官方文档:source.android.com/security/ap…

3.1 V1签名

3.1.1 V1签名机制

image.png

3.1.2 签名流程

  1. 计算每一个原始文件的 SHA-1 摘要,写入到 MANIFEST.MF 中;
  2. 计算整个 MANIFEST.MF 文件的 SHA-1 摘要,写入到 CERT.SF 中;
  3. 计算 MANIFEST.MF 中,每一块的 SHA-1 摘要,写入到 CERT.SF 中;
  4. 计算整个 CERT.SF 文件的摘要,使用开发者私钥计算出摘要的签名;
  5. 将签名和开发者证书(X.509)写入 CERT.RSA 。

3.1.3 签名校验流程

  1. 取出 CERT.RSA 中包含的开发者证书;
  2. 通过系统的根证书(CA证书)验证这个开发者证书是否可信;
  3. 如果开发者证书可信,用证书中的公钥解密 CERT.RSA 中包含的签名。
  4. 计算 CERT.SF 的签名;
  5. 对比 (3) 和 (4) 的签名是否一致;
  6. 如果一致,用 CERT.SF 去校验 MANIFEST.MF 是否被修改;
  7. 如果没有被修改,再用 MANIFEST.MF 中的每一块数据去校验每一个文件是否被修改。

3.1.4签名如何防止篡改 假如攻击者修改了其中某一个文件,那么他必须修改 MANIFEST.MF 中对应文件的摘要,否则这个文件校验不通过; 接着还得修改 CERT.SF 中的摘要,否则摘要校验不过; 还得重新计算 CERT.SF 的签名,否则签名校验不通过; 但是计算签名需要私钥,私钥在开发者手中,攻击者没有私钥,所以无法签名。

3.1.5 签名存在的问题 校验速度慢:需要对 apk 中的每个文件都计算摘要并验证,如果文件很多,校验时间会很长。 完整性不够:V1 签名只会校验 Zip 文件中的部分文件,例如 META-INFO 文件夹就不会参与校验。

3.2 V2签名 V2 签名是在 Android7.0 之后引入的,它解决了 V1 签名校验时速度慢的问题,同时对完整性的校验扩展到整个安装包。

3.2.1 Zip文件格式和解析过程

image.png

  1. 先从文件尾部查找 0x06054b50,确定 End Of Central Directory Record 区域的起始位置;
  2. 解析 EoCD 区域,并获得中央目录的起始位置;
  3. 根据起始位置,逐个解析文件。

从解析过程可以看出,如果在 「文件信息部分」 和 「中央目录部分」之间插入了其他数据,是不会影响 Zip 文件的解压缩的。 3.2.2 签名数据块的格式 3.2.2.1 签名前后对比图 V2 签名时,会将 签名信息块 插入到 Zip 文件的「文件信息」和「中央目录」之间,签名前后对比图:

image.png

3.2.2.2 「Apk Signing Block」的具体结构:

image.png

签名块的前8个字节记录了所有键值对数据块的大小。其后紧接着键值对数据块,数据块由一个个的键值对块组成。 每个键值对块的开始8字节记录了「键值对的ID」和「键值对的Value」的大小。接下来4字节是键值对的ID,后面跟着对应的值。 ID = 0x7109871a 的键值对块就是保存签名信息的地方。 键值对数据块的后面还有8个字节,也是用于记录「键值对块」的大小,它的值和最开始的8字节相同。 签名块的末尾是一个魔数,也就是‘APK Sig Block 42’的 ASCII 码。 3.2.2.3 签名信息的具体结构:

image.png 3.2.3 摘要计算方式 V2 签名摘要的计算就不是按照文件计算的了,而是按照 1MB 为单位计算:

image.png 步骤:

  1. 对原始apk文件的 文件信息部分、中央目录部分、EoCD部分,按照 1MB 大小分割为多个小块(Chunks);
  2. 分别对每一个小块计算其摘要,类似于 V1 签名中的 MANIFEST.MF 文件;
  3. 对(2)中所有摘要计算其摘要,类似于 V1 签名中的 CERT.SF 文件;

3.2.4 签名的校验 Android 7.0 及以上在校验时,会先判断是否具有 V2 签名,如果有 V2 签名,会走 V2 签名的校验流程,不再验证V1签名了。 如何判断是否有V2签名? 根据Zip文件格式的规则,我们可以找到中央目录区的起始位置。 读取从起始位置开始往回的16个字节,判断这16个字节的值是否为 "Apk Sig Block 42",如果是,则对应上了魔数,说明有 V2 签名。后续就是解析 V2 签名块的流程了。 用公钥和签名对蓝色区域验证,验证通过后,用 「APK数据摘要集」对APK每一块做验证。 3.3 V3签名 V3 签名方案的签名块格式和V2完全一样,只是 V2 的签名块信息存放在 ID = 0x7109871a 的数据块中,而 V3 的签名信息存放在 ID = 0xf05368c0 的数据块中。 在这个新的数据块中,记录了旧的签名信息和新的签名信息,以密钥转轮的方案,做签名的替换和升级。这意味着我们可以更改 APK 的签名。 V3 签名块的大小必须是 4096 的整数倍,否则在安装时会出现如下异常 adb: failed to install xxx.apk: Failure [INSTALL_PARSE_FAILED_NO_CERTIFICATES: Failed to collect certificates from /data/app/xxxx.apk using APK Signature Scheme v3: Size of APK Signing Block is not a multiple of 4096: xxxx]

3.4 V4签名 Android 11 通过 APK 签名方案 v4 支持与流式传输兼容的签名方案。v4 签名基于根据 APK 的所有字节计算得出的 Merkle 哈希树。它完全遵循 fs-verity 哈希树的结构(例如,对盐进行零填充,以及对最后一个分块进行零填充。)Android 11 将签名存储在单独的 .apk.idsig 文件中。v4 签名需要 v2 或 v3 签名作为补充。

3.4.1文件格式 所有数字字段均采用小端字节序。所有字段占据的字节数均与其 sizeof() 相同,而不会添加隐式填充或对齐。 以下辅助结构体可简化相关定义。 主文件内容: 关键术语:如果 v4 签名包含 Merkle 树,则称为 complete;如果不包含 Merkle 树,则为 stripped。hashing_info 是用于哈希树生成及根哈希的参数: signing_info 为以下结构体: 注意:signing_info 会作为二进制文件数据 blob 整体传递到 IncFS 驱动程序中。内核会提供一个 ioctl,以便与 hashing_info 一起检索。

  • apk_digest 取自 APK 的 v3 签名分块;如果没有该分块,则取自 v2 分块(请参阅 apk_digest)

若要创建及验证 signature 代码,必须将以下数据序列化为二进制 blob 并将其作为签名数据传递到签名/验证算法中:

  1. merkle_tree 是 APK 的整个 Merkle 树,其计算方式如 fs-verity 文档中所述。

注意:此字段为可选字段,如果处理工具可获取整个 AKP,则签名中可以缺少此字段。然后,此工具需要重新计算该树。

3.4.2生产方和使用方 如果您使用默认参数运行 v4 签名文件,apksigner Android SDK 工具现在会生成 v4 签名文件。您可以按照与其他签名方案一样的方式停用 v4 签名。它还可以验证 v4 签名是否有效。 运行 adb install --incremental 命令时,adb 会要求 .apk.idsig 文件存在于 .apk 旁边 默认情况下,它还会使用 .idsig 文件尝试进行增量安装;如果此文件缺失或无效,该命令会回退到常规安装。 创建安装会话后,PackageInstaller 中的新流式传输安装 API 会在将文件添加到会话时,将剥离的 v4 签名作为一项单独的参数加以接受。此时,signing_info 将作为整个 blob 传递到 IncFS 中。IncFS 从 blob 中提取根哈希。 提交安装会话时,PackageManagerService 会执行 ioctl 以从 IncFS 中检索 signing_info blob,对其进行解析并验证签名。 增量数据加载器组件应通过数据加载器原生 API 流式传输签名的 Merkle 树部分。 package 服务 shell 命令 install-incremental 会将剥离的 v4 签名文件(以 Base64 编码)作为添加的每个文件的一项参数加以接受。相应 Merkle 树必须发送到命令的 stdin 中。

3.4.3apk_digest apk_digest 是第一个可用的内容摘要(按顺序排列):

  1. V3、1MB 分块、SHA2-512 (CONTENT_DIGEST_CHUNKED_SHA512)、
  2. V3、4KB 分块、SHA2-256 (CONTENT_DIGEST_VERITY_CHUNKED_SHA256)、
  3. V3、1MB 分块、SHA2-256 (CONTENT_DIGEST_CHUNKED_SHA256)、
  4. V2、SHA2-512、
  5. V2、SHA2-256。

请参阅 APK 签名方案 v3 中的带长度前缀的签名的(带长度前缀)序列。

image.png

图 1:APK 验证流程 v4

3.4.4验证和测试 使用功能单元测试和 CTS 验证实现。

  • CtsIncrementalInstallHostTestCases
    • /android/cts/hostsidetests/incrementalinstall

测试签名格式 若要测试签名格式,请设置开发环境并运行以下手动测试: $ atest PackageManagerShellCommandTest PackageManagerShellCommandIncrementalTest

使用 Android SDK(ADB 和 apksigner)测试签名格式 若要使用 Android SDK 测试签名格式,请设置开发环境,并确保您已完成 IncFS 的实现。然后,在目标实体设备或模拟器上刷写相应 build。您需要生成或获取现有的 APK,然后创建调试签名密钥。最后,使用 build-tools 文件夹中的 v4 签名格式对 APK 进行签名和安装。 签名 ./apksigner sign --ks debug.keystore game.apk

安装 ./adb install game.apk

在哪里可以找到这些测试? /android/cts/tests/tests/content/src/android/content/pm/cts/PackageManagerShellCommandIncrementalTest.java

分类:
Android
标签: