Android 11 通過 APK 簽名方案 v4 支持流兼容的簽名方案。 v4 簽名基於對 APK 的所有字節計算的 Merkle 哈希樹。它完全遵循fs-verity哈希樹的結構(例如,零填充鹽和零填充最後一個塊)。 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
作為一個整體傳遞到 incfs 中。 Incfs 從 blob 中提取根哈希。
提交安裝會話時,PackageManagerService 執行 ioctl 以從 incfs 檢索signing_info blob,對其進行解析並驗證簽名。
增量數據加載器組件有望通過數據加載器原生 API 流式傳輸簽名的 Merkle 樹部分。
package
service 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