APK簽名方案v2

APK簽名方案v2是一種全文件簽名方案,可通過檢測APK的受保護部分的任何更改來提高驗證速度並增強完整性保證

使用APK簽名方案v2簽名會在ZIP中央目錄部分之前的APK文件中插入一個APK簽名塊。在APK簽名塊中,v2簽名和簽名者身份信息存儲在APK簽名方案v2塊中

簽名前後的APK

圖1.簽名前後的APK

APK簽名方案v2在Android 7.0(牛軋糖)中引入。要使APK可在Android 6.0(棉花糖)和較舊的設備上安裝,請先使用JAR簽名對APK進行簽名,然後再使用v2方案進行簽名。

APK簽名塊

為了保持與v1 APK格式的向後兼容性,v2和更新的APK簽名存儲在APK簽名塊中,APK簽名塊是一個引入的新容器,用於支持APK簽名方案v2。在APK文件中,APK簽名塊位於ZIP中央目錄的緊前面,ZIP中央目錄位於文件的末尾。

該區塊包含ID值對,其包裝方式使在APK中更容易找到該區塊。 APK的v2簽名存儲為ID值為ID 0x7109871a的ID值對。

格式

APK簽名塊的格式如下(所有數字字段均為little-endian):

  • size of block以字節為單位)(不包括該字段)(uint64)
  • uint64長度前綴的ID值對的序列:
    • ID (uint32)
    • value (可變長度:線對的長度-4個字節)
  • size of block以字節為單位)-與第一個字段(uint64)相同
  • magic “ APK Sig Block 42”(16字節)

首先通過找到ZIP中央目錄的開始來解析APK(通過在文件末尾找到“中央目錄的ZIP結束”記錄,然後從記錄中讀取“中央目錄”的開始偏移)。 magic值提供了一種快速的方法來確定Central Directory之前的內容可能是APK簽名塊。然後size of block值的size of block有效地指向文件中塊的開始。

解釋該塊時,應忽略具有未知ID的ID值對。

APK簽名方案v2塊

APK由一個或多個簽名者/身份簽名,每個簽名者/身份由一個簽名密鑰表示。此信息存儲為APK簽名方案v2塊。對於每個簽名者,將存儲以下信息:

  • (簽名算法,摘要,簽名)元組。存儲摘要以使簽名驗證與APK內容的完整性檢查脫鉤。
  • 代表簽名者身份的X.509證書鏈。
  • 其他屬性作為鍵值對。

對於每個簽名者,都會使用提供的列表中受支持的簽名來驗證APK。具有未知簽名算法的簽名將被忽略。遇到多個受支持的簽名時,由每個實現決定選擇使用哪個簽名。這樣可以在將來以向後兼容的方式引入更強大的簽名方法。建議的方法是驗證最強的簽名。

格式

APK簽名方案v2塊存儲在APK簽名塊中,其ID為0x7109871a

APK簽名方案v2塊的格式如下(所有數值均為little-endian,所有帶前綴的字段均使用uint32作為長度):

  • 長度前綴signer的長度前綴序列:
    • 長度前綴的signed data
      • 長度前綴digests的長度前綴序列:
      • X.509 certificates長度前綴序列:
        • 長度前綴的X.509 certificate (ASN.1 DER格式)
      • 長度前綴的additional attributes的長度前綴序列:
        • ID (uint32)
        • value (可變長度:附加屬性的長度-4個字節)
    • 長度signatures序列的長度前綴序列:
      • signature algorithm ID (uint32)
      • 長度超過signed data signature
    • 長度前綴的public key (SubjectPublicKeyInfo,ASN.1 DER形式)

簽名算法ID

  • 0x0101-具有SHA2-256摘要,SHA2-256 MGF1、32字節鹽,預告片的RSASSA-PSS:0xbc
  • 0x0102-具有SHA2-512摘要的SHASSA-PSS,SHA2-512 MGF1,64字節鹽,預告片:0xbc
  • 0x0103-具有SHA2-256摘要的RSASSA-PKCS1-v1_5。這用於需要確定性簽名的構建系統。
  • 0x0104-具有SHA2-512摘要的RSASSA-PKCS1-v1_5。這用於需要確定性簽名的構建系統。
  • 0x0201-具有SHA2-256摘要的ECDSA
  • 0x0202-具有SHA2-512摘要的ECDSA
  • 0x0301-具有SHA2-256摘要的DSA

以上所有簽名算法均受Android平台支持。簽名工具可以支持算法的子集。

支持的鍵大小和EC曲線:

  • RSA:1024、2048、4096、8192、16384
  • EC:NIST P-256,P-384,P-521
  • DSA:1024、2048、3072

完整性保護的內容

為了保護APK內容,APK由四個部分組成:

  1. ZIP條目的內容(從偏移量0到APK簽名塊開始)
  2. APK簽名塊
  3. ZIP中央目錄
  4. 中央目錄的ZIP結尾

簽名後的APK部分

圖2.簽名後的APK部分

APK簽名方案v2保護第1、3、4節以及第2節中包含的APK Signature Scheme v2塊的signed data塊的完整性。

部分1、3和4的完整性受到存儲在已signed data塊中的內容的一個或多個摘要的保護,這些摘要又又受一個或多個簽名保護。

類似於兩級Merkle樹,按以下方式計​​算部分1、3和4的摘要。每個部分被分成連續的1 MB(2個20字節)的塊。每個部分中的最後一個塊可能會更短。每個塊的摘要是通過字節0xa5的串聯,塊的長度(以字節為單位)(little-endian uint32)以及塊的內容來計算的。頂級摘要是根據字節0x5a的串聯,塊的數量(小尾數uint32)和塊的摘要的串聯(按塊在APK中出現的順序)計算的。摘要以分塊方式進行計算,以通過並行化來加快計算速度。

APK摘要

圖3. APK摘要

第4節(ZIP中央目錄的末尾)的保護由於包含ZIP中央目錄的偏移量的部分而變得複雜。當APK簽名塊的大小更改時(例如,添加新簽名時),偏移量也會更改。因此,在中央目錄的ZIP端上計算摘要時,必須將包含ZIP中央目錄偏移量的字段視為包含APK簽名塊的偏移量。

回滾保護

攻擊者可能嘗試將v2簽名的APK驗證為在支持驗證v2簽名的APK的Android平台上作為v1簽名的APK。為了緩解這種攻擊,具有v1簽名的v2簽名APK必須在其META-INF / *。SF文件的主要部分中包含X-Android-APK-Signed屬性。該屬性的值是一組用逗號分隔的APK簽名方案ID(此方案的ID為2)。在驗證v1簽名時,要求APK驗證程序拒絕對於驗證程序從該集合中偏愛的APK簽名方案(例如v2方案)不具有簽名的APK。這種保護依賴於以下事實:內容META-INF / *。SF文件受v1簽名保護。請參閱有關JAR簽名的APK驗證的部分。

攻擊者可能試圖從APK簽名方案v2塊中剝離更強的簽名。為了減輕這種攻擊,與APK進行簽名的簽名算法ID的列表存儲在已signed data塊中,該signed data塊受每個簽名保護。

確認

在Android 7.0及更高版本中,可以根據APK簽名方案v2 +或JAR簽名(v1方案)對APK進行驗證。較舊的平台會忽略v2簽名,而只會驗證v1簽名。

APK簽名驗證過程

圖4. APK簽名驗證過程(紅色中的新步驟)

APK簽名方案v2驗證

  1. 找到APK簽名塊並驗證:
    1. APK簽名塊的兩個大小字段包含相同的值。
    2. ZIP中央目錄後緊跟中央目錄記錄的ZIP末尾。
    3. 中央目錄的ZIP末尾沒有更多數據。
  2. 在APK簽名塊中找到第一個APK簽名方案v2塊。如果存在v2塊,請繼續執行步驟3。否則,請退回到使用v1方案驗證APK。
  3. 對於APK簽名方案v2塊中的每個signer
    1. signatures選擇最受支持的signature algorithm ID 。強度排序取決於每個實現/平台版本。
    2. 驗證相應的signaturesignatures反對signed data使用public key 。 (現在可以安全地分析signed data 。)
    3. 驗證digestssignatures中籤名算法ID的排序列表是否相同。 (這是為了防止簽名剝離/添加。)
    4. 使用與簽名算法使用的摘要算法相同的摘要算法計算APK內容的摘要。
    5. 驗證所計算的摘要是等同於相應的digestdigests
    6. 驗證第一的是SubjectPublicKeyInfo進行certificatecertificates是相同的public key
  4. 如果至少找到一個signer則驗證成功,並且對於每個找到的signer ,步驟3成功。

注意:如果在步驟3或4中失敗,則不得使用v1方案驗證APK。

JAR簽名的APK驗證(v1方案)

JAR簽名的APK是標準的簽名JAR ,它必須完全包含META-INF / MANIFEST.MF中列出的條目,並且所有條目都必須由同一組簽名者簽名。驗證其完整性如下:

  1. 每個簽名者均由META-INF / <signer> .SF和META-INF / <signer>。(RSA | DSA | EC)JAR條目表示。
  2. <signer>。(RSA | DSA | EC)是具有SignedData結構PKCS#7 CMS ContentInfo,其簽名已通過<signer> .SF文件驗證。
  3. <signer> .SF文件包含META-INF / MANIFEST.MF的完整文件摘要以及META-INF / MANIFEST.MF的每個部分的摘要。 MANIFEST.MF的整個文件摘要已得到驗證。如果失敗,則改為驗證每個MANIFEST.MF節的摘要。
  4. 對於每個受完整性保護的JAR條目,META-INF / MANIFEST.MF都包含一個相應命名的部分,其中包含該條目未壓縮內容的摘要。所有這些摘要均已驗證。
  5. 如果APK包含未在MANIFEST.MF中列出且不屬於JAR簽名的JAR條目,則APK驗證將失敗。

因此,保護鍊為每個完整性受保護的JAR條目的<簽名者>。(RSA | DSA | EC)-> <簽名者> .SF-> MANIFEST.MF->內容。