Android 11 通过 APK 签名方案 v4 支持流式兼容的签名方案。v4 签名基于对 APK 的所有字节计算的 Merkle 哈希树。它完全遵循 fs-verity 哈希树的结构(例如,对 salt 进行零填充和对最后一个块进行零填充)。Android 11 将签名存储在单独的文件 <apk name>.apk.idsig
中。v4 签名需要补充的 v2 或 v3 签名。
文件格式
所有数字字段均为小端字节序。所有字段占用的字节数与其 sizeof()
完全相同,不添加隐式填充或对齐。
以下是一个辅助结构体,用于简化定义。
template <class SizeT> struct sized_bytes { SizeT size; byte bytes[size]; };
主文件内容
struct V4Signature { int32 version; // only version 2 is supported as of now sized_bytes<int32> hashing_info; sized_bytes<int32> signing_info; sized_bytes<int32> merkle_tree; // optional };
hashing_info
是用于哈希树生成的参数 + 根哈希
struct hashing_info.bytes { int32 hash_algorithm; // only 1 == SHA256 supported int8 log2_blocksize; // only 12 (block size 4096) supported now sized_bytes<int32> salt; // used exactly as in fs-verity, 32 bytes max sized_bytes<int32> raw_root_hash; // salted digest of the first Merkle tree page };
signing_info
是以下结构体
struct signing_info.bytes { sized_bytes<int32> apk_digest; // used to match with the corresponding APK sized_bytes<int32> x509_certificate; // ASN.1 DER form sized_bytes<int32> additional_data; // a free-form binary data blob sized_bytes<int32> public_key; // ASN.1 DER, must match the x509_certificate int32 signature_algorithm_id; // see the APK v2 doc for the list sized_bytes<int32> signature; };
apk_digest
取自 APK 的 v3 签名块,如果不存在,则取自 v2 块(请参阅 apk_digest)
要创建和验证 signature
,代码必须将以下数据序列化为二进制 blob,并将其作为签名数据传递到签名/验证算法中
struct V4DataForSigning { int32 size; int64 file_size; // the size of the file that's been hashed. hashing_info.hash_algorithm; hashing_info.log2_blocksize; hashing_info.salt; hashing_info.raw_root_hash; signing_info.apk_digest; signing_info.x509_certificate; signing_info.additional_data; };
merkle_tree
是 APK 的完整 Merkle 树,其计算方法如 fs-verity 文档中所述。
生产者和消费者
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
接受编码为 base64 的剥离 v4 签名文件作为每个添加文件的参数。相应的 Merkle 树必须发送到命令的 stdin
中。
apk_digest
apk_digest
是按顺序排列的第一个可用的内容摘要
- V3,1MB 块,SHA2-512 (CONTENT_DIGEST_CHUNKED_SHA512),
- V3,4KB 块,SHA2-256 (CONTENT_DIGEST_VERITY_CHUNKED_SHA256),
- V3,1MB 块,SHA2-256 (CONTENT_DIGEST_CHUNKED_SHA256),
- V2,SHA2-512,
- V2,SHA2-256。
请参阅 APK 签名方案 v3 中的长度前缀的签名序列。

验证和测试
使用功能单元测试和 CTS 验证实现。
CtsIncrementalInstallHostTestCases
- /android/cts/hostsidetests/incrementalinstall
测试签名格式
要测试签名格式,设置开发环境 并运行以下手动测试
$ atest PackageManagerShellCommandTest
PackageManagerShellCommandIncrementalTest
使用 Android SDK(ADB 和 apksigner)测试签名格式
要使用 Android SDK 测试签名格式,设置开发环境 并确保您已完成 IncFS 的实施。然后将构建刷入目标物理设备或模拟器。您需要生成或获取现有 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