Android APP签名机制
通过应用签名,开发者可以标识应用创作者并更新其应用,而无需创建复杂的接口和权限。在 Android 平台上运行的每个应用都必须要开发者签名。Google Play 或 Android 设备上的软件包安装程序会拒绝没有经过签名就尝试安装的应用。
Android 支持以下四种应用签名方案:
- v1 方案:基于 JAR 签名。
- v2 方案:APK 签名方案 v2(在 Android 7.0 中引入)。
- v3 方案:APK 签名方案 v3(在 Android 9 中引入)。
- v4方案:APK 签名方案 v4 (在Android 11中引入)。
APK签名方案 v1
其完整性按照以下方式进行验证:
- 每个签名者均由一个包含 META-INF/CERT.SF 和 META-INF/CERT.(RSA|DSA|EC) 的 JAR 条目表示。
- CERT.(RSA|DSA|EC) 是具有 SignedData 结构的 PKCS #7 CMS ContentInfo,其签名通过 CERT.SF 进行验证。
- CERT.SF 文件包含 META-INF/MANIFEST.MF 的全文件摘要和 META-INF/MANIFEST.MF 各个部分的摘要。需要验证 MANIFEST.MF 的全文件摘要。如果该验证失败,则改为验证 MANIFEST.MF 各个部分的摘要。
- 对于每个受完整性保护的 JAR 条目,META-INF/MANIFEST.MF 都包含一个具有相应名称的部分,其中包含相应条目未压缩内容的摘要。所有这些摘要都需要验证。
- 如果 APK 包含未在 MANIFEST.MF 中列出且不属于 JAR 签名一部分的 JAR 条目,APK 验证将会失败。
因此,保护链是每个受完整性保护的 JAR 条目的 CERT.(RSA|DSA|EC) -> CERT.SF -> MANIFEST.MF -> 内容。
MANIFEST.MF
该文件中保存的内容其实就是逐一遍历 APK 中的所有条目,如果是目录就跳过,如果是一个文件,就用 SHA256消息摘要算法提取出该文件的摘要然后进行 BASE64 编码后,作为「SHA-256-Digest」属性的值写入到 MANIFEST.MF 文件中的一个块中
CERT.SF
SHA-256-Digest-Manifest:对整个 MANIFEST.MF 文件做SHA256后再用 Base64 编码
SHA-256-Digest:对 MANIFEST.MF 的各个条目做 SHA256后再用 Base64 编码
CERT.RSA
把 CERT.SF 文件,用私钥计算出签名, 然后将签名以及包含公钥信息的数字证书一同写入 CERT.RSA 中保存。Android APK 中的 CERT.RSA 证书是自签名的,并不需要这个证书是第三方权威机构发布或者认证的,用户可以在本地机器自行生成这个自签名证书。
可以使用如下命令查看证书:
1 |
|
windows 的openssl可以在这个网站下载:Win32/Win64 OpenSSL Installer for Windows - Shining Light Productions
APK签名方案 v2
APK signature scheme v2 | Android Open Source Project
APK签名方案v2是一种全文件签名方案,该方案可以防止对APK受保护部分进行的更改;使用v2签名方案时会在APK文件中插入一个APK签名分块。APK 签名方案 v2 分块存储在 APK 签名分块内,ID 为 0x7109871a
v2签名后的apk包含四个部分:
- ZIP 条目的内容(从偏移量 0 处开始一直到 APK 签名分块的起始位置)
- APK 签名分块
- ZIP 中央目录
- ZIP 中央目录结尾
其中,应用签名方案的签名信息会被保存在 区块 2(APK Signing Block)中,而区块 1(Contents of ZIP entries)、区块 3(ZIP Central Directory)、区块 4(ZIP End of Central Directory)是受保护的,在签名后任何对区块 1、3、4 的修改都逃不过新的应用签名方案的检查。
签名
第 1、3 和 4 部分的摘要采用以下计算方式,类似于两级 Merkle 树。每个部分都会被拆分成多个大小为 1MB的连续块。每个部分的最后一个块可能会短一些。每个块的摘要均通过字节 0xa5
的串联、块的长度(采用小端字节序的 uint32 值,以字节数计)和块的内容进行计算。顶级摘要通过字节 0x5a
的串联、块数(采用小端字节序的 uint32 值)以及块的摘要的串联(按照块在 APK 中显示的顺序)进行计算。摘要以分块方式计算,以便通过并行处理来加快计算速度:
由于第 4 部分(ZIP 中央目录结尾)包含“ZIP 中央目录”的偏移量,因此该部分的保护比较复杂。当 APK 签名分块的大小发生变化(例如,添加了新签名)时,偏移量也会随之改变。因此,在通过“ZIP 中央目录结尾”计算摘要时,必须将包含“ZIP 中央目录”偏移量的字段视为包含 APK 签名分块的偏移量。
验签
找到 APK 签名分块并验证以下内容:
- APK 签名分块的两个大小字段包含相同的值。
- “ZIP 中央目录结尾”紧跟在“ZIP 中央目录”记录后面。
- “ZIP 中央目录结尾”之后没有任何数据。
找到 APK 签名分块中的第一个 APK 签名方案 v2 分块。如果 v2 分块存在,则继续执行第 3 步。否则,回退至使用 v1 方案验证 APK。
先使用公钥验证第二个区块的签名,保证第二个区块没有被篡改,然后去计算1、3、4部分的摘要值是否与签名的摘要值一致