美文网首页
Android签名的问题

Android签名的问题

作者: 钦秋 | 来源:发表于2020-12-03 14:54 被阅读0次

    今天下载Android Studio 4.2 Canary16,本意是想了解和使用一下Jetpack Compose,但是在新特新中看到支持V3和V4签名格式。瞬间有时代脱节的感觉,要不先来了解一下签名格式的变动好了。

    然后在官方文档我又看到了
    Android Gradle 插件 4.2 现在支持 v3 和 v4 APK 签名格式。如需在 build 中启用这两种格式之一或同时启用这两种格式,请将以下属性添加到模块级 build.gradle 或 build.gradle.kts 文件中:

    ??? build.gradle.kts这是啥摸不着头脑Kotlin DSL。哎,继续了解吧。

    KOTLIN
    // build.gradle.kts
    
    android {
       ...
       signingConfigs {
          config {
              ...
              enableV3Signing(true)
              enableV4Signing(true)
          }
       }
    }
    
    GROOVY
    // build.gradle
    
    android {
      ...
      signingConfigs {
        config {
            ...
            enableV3Signing true
            enableV4Signing true
        }
      }
    }
    

    Android签名的方案

    • v1方案:基于JAR签名
    • v2方案:Android 7.0加入
    • v3方案:Android 9.0加入

    一、v1签名的过程

    解压一个APK会在里面看见一个META-INF的文件夹。
    目录结构大致如下:

    xxxxx/
        |- META-INF/
        |        |- CERT.RSA
        |        |- CERT.SF
        |        |- MANIFEST.MF
        | ......
    

    MANIFEST.MF

    Manifest-Version: 1.0
    Built-By: Signflinger
    Created-By: Android Gradle 4.1.1
    
    Name: AndroidManifest.xml
    SHA-256-Digest: Z7PLvLjebGnXnpd9lKFoEprfDAZblEKKT5lDH3sRDL8=
    
    Name: DebugProbesKt.bin
    SHA-256-Digest: q21I1dhoxzPNAzRfiquuPZBb1vD8ZhEXqL3+psUbknQ=
    
    Name: META-INF/androidx.activity_activity.version
    SHA-256-Digest: WYVJhIUxBN9cNT4vaBoV/HkkdC+aLkaMKa8kjc5FzgM=
    

    文件里面储存了APK中所有Name:文件的路径和SHA-256-Digest的值
    SHA-256-Digest计算方式

    shasum -a 256 xxx.xx
    

    然后计算base64的值

    CERT.SF

    Signature-Version: 1.0
    Created-By: Android Gradle 4.1.1
    SHA-256-Digest-Manifest: Wkyr/WgaCc7qm2F+eEfAQkGPoFUxZk/Y8Ix5qAmZN3w=
    
    Name: AndroidManifest.xml
    SHA-256-Digest: v5I/yMuPghplj0AMllLy3ono40APuAf1p/G28Bg6QuU=
    
    Name: DebugProbesKt.bin
    SHA-256-Digest: lGNfZfenjO/ig36HyxY3o4SsvfGGgP0dK+OSY20ejcw=
    
    Name: META-INF/androidx.activity_activity.version
    SHA-256-Digest: Yu1eiqd7wti3kPabgLC0lsO+1ns/UAhiPGUExHOxH/w=
    

    SF文件的内容和MF文件非常相似,同样包含了APK的所以文件摘要。
    区别:

    • SF文件记录了整个MF文件的摘要
    • SF文件其余部分记录MF相应条目的摘要

    CERT.RSA

    CERT.REA里面是二进制内容,里面保存了签名的证书信息,以及对CERT.SF文件的签名。

    通过下面的命令可以查看证书里面的信息

    $ openssl pkcs7 -inform DER -in XXX/META-INF/CERT.RSA -text -noout -print_certs
    

    内容如下:

    Certificate:
        Data:
            Version: 3 (0x2)
            Serial Number: 1715685340 (0x664347dc)
        Signature Algorithm: sha256WithRSAEncryption
            Issuer: C=1, ST=1, L=1, O=1, OU=11, CN=1
            Validity
                Not Before: Apr  7 05:55:19 2020 GMT
                Not After : Apr  1 05:55:19 2045 GMT
            Subject: C=1, ST=1, L=1, O=1, OU=11, CN=1
            Subject Public Key Info:
                Public Key Algorithm: rsaEncryption
                    Public-Key: (2048 bit)
                    Modulus:
                        00:9d:65:5c:da:fd:50:3c:81:b7:70:45:47:bb:94:
                        73:07:06:cc:96:76:c8:a1:86:1d:6a:ee:f9:ff:1e:
                        59:1a:8d:0f:21:e1:b0:7a:c8:c3:11:32:c3:9d:6f:
                        85:e3:51:74:35:aa:16:df:52:97:1d:a5:c7:26:6a:
                        a3:96:92:e2:89:31:76:5e:62:10:2a:46:a6:70:dd:
                        40:48:72:cb:33:70:fc:e0:de:5c:fd:59:5c:ce:bc:
                        ca:c4:8a:68:da:4d:40:ac:49:1e:21:dc:a8:51:7c:
                        56:9b:6e:ae:93:67:2c:9d:ed:ca:2d:03:6a:19:84:
                        0d:7c:3d:28:b1:bf:a3:86:38:ca:cb:18:29:2d:77:
                        bb:6e:ee:10:70:af:e7:ff:67:36:a6:3c:dc:06:63:
                        b8:27:be:7f:c0:2f:98:66:00:cd:69:5f:24:7f:24:
                        3f:d6:21:36:7b:7c:2b:57:ea:2a:4b:8d:d4:43:bb:
                        ae:c7:91:56:83:3e:f8:61:fa:e8:89:76:89:ad:ca:
                        a8:9d:c6:d9:db:89:69:5b:6f:56:3d:7f:c9:91:51:
                        ee:bf:2e:76:94:5b:a8:4e:da:99:b5:bd:00:ac:ee:
                        c0:72:02:0d:ae:14:9c:53:30:5f:cc:55:07:1c:a6:
                        eb:e3:b6:b6:dc:01:1e:8a:7e:1e:01:a1:95:bb:21:
                        02:a5
                    Exponent: 65537 (0x10001)
            X509v3 extensions:
                X509v3 Subject Key Identifier:
                    E1:FD:95:4D:84:C9:20:E8:BA:17:68:42:9A:F4:B9:C3:80:1F:15:7E
        Signature Algorithm: sha256WithRSAEncryption
             23:09:e0:4e:85:bb:7e:ac:9b:3e:20:21:9d:7d:85:d7:f9:6b:
             49:d3:02:cd:3e:13:af:bc:24:34:98:1f:a9:fc:22:7e:5a:dd:
             35:60:33:e6:9b:e5:58:b4:fe:cf:84:1b:50:8c:83:b0:74:8e:
             a8:44:fc:cf:20:28:20:d1:d2:76:26:d7:0f:56:29:55:34:8e:
             bd:8a:84:68:09:5c:3c:da:3f:44:f7:e0:2b:17:13:e6:72:65:
             b4:07:b2:e3:57:99:2a:e4:26:12:20:74:3c:21:b5:b6:f5:49:
             8b:9d:6d:25:0b:e3:d0:02:10:f8:33:95:3f:e7:76:87:57:57:
             30:5c:f5:1e:6b:b3:a5:2d:96:0e:1d:9a:29:2b:44:67:ae:e3:
             cf:13:7f:be:c3:e6:ec:6d:e0:3d:b3:10:d4:a3:d0:6f:c1:7b:
             17:16:5c:09:a7:e8:d0:aa:4c:dd:ec:7f:25:eb:f4:0d:bd:a6:
             0e:20:94:7f:53:ec:89:39:06:70:3b:f2:31:45:6f:d9:30:92:
             85:df:ec:9f:14:ec:d2:57:c1:45:51:f6:ec:78:71:cb:48:94:
             80:ae:3e:24:a1:6f:7a:ee:dd:1d:4c:23:72:ff:89:0a:51:93:
             7e:23:d0:b6:a6:f7:b2:82:b2:85:5d:f2:4a:c0:26:6b:3b:bb:
             60:f9:69:9d
    

    APK校验过程简述

    • 首先校验CERT.SF文件的签名
    • 校验MINIFEST.MF文件的完整性
    • 校验APK中每个文件的完整性
    • 校验签名的一致性(app升级时)

    V1签名机制的劣势

    • 签名校验速度慢

      校验过程中需要对所有文件进行摘要计算,apk资源越多机器性能越差安装速度越慢

    • 完整性保障不够

      META-INF没有计入签名校验过程中,可以随意在这个目录中添加文件(比如可以添加渠道标识)

    为了解决这些问题从Android 7.0开始,Android支持了一套新的v2签名机制。

    二、V2签名机制

    前言:

    了解v2签名的机制之前需要先简单了解一下zip文件的组成

    压缩文件数据区+压缩源文件目录区+压缩源文件目录结束标志

    1. 数据区(压缩文件数据区)
      包含zip文件中所有文件的记录,一个列表,每条记录包含:文件名、压缩前后size、压缩后的数据等
    2. 中央目录(压缩源文件目录区)
      存放目录信息,一个列表,每条记录包含:文件名、压缩前后size、本地文件头的起始偏移量等。通过本地文件头的起始便宜量即可找到压缩后的数据。
    3. 中央目录结尾记录(压缩源文件目录结束标记)
      标识压缩文件的目录结尾,包含:中央目录条目数、size、起始偏移量、zip文件注释内容等。

    通过压缩源文件中央目录起始偏移量可和size可以定位到中央目录,遍历文件目录条目,根据本地文件头的起始偏移量即可在数据区中找到相应的压缩数据。

    2.1 V2签名原理
    • jar签名:是在apk文件中添加META-INF目录,即需要修改数据区中央目录中插入数据,添加文件后会导致中央目录大小和偏移量发生变化,还需要修改目录结束标记。
    • v2签名方案:在数据区和中央目录中间插入数据,一个APK签名分块,从而保证原始zip(apk)数据的完整性。

    v2签名块负责保护数据区、中央目录、中央目录结尾记录部分的完整性,以及APK 签名方案 v2分块中的singed data分块的完整性。

    APK 签名方案 v2分块是一个签名序列,包含三个内容:

    • 带长度前缀的signed data
      包含了一系列算法计算的摘要列表、证书信息,以及extra信息(可选)
    • 带长度前缀的signatures序列
      通过一系列算法对singed data的签名列表。签名时使用了多个签名算法,在签名校验时吗,选择系统支持的安全系数最大的签名进行校验。
    • 证书公钥
    2.2 保证完整性摘要的计算过程

    v2签名块负责保护数据区、中央目录、中央目录结尾记录部分的完整性,以及APK 签名方案 v2分块中的signed data分块的完整性

    保证完整性打的具体措施:

    • 通过内容摘要的方式保护数据区、中央目录、中央目录结尾记录的完整性->保存在singed data分块中
    • 通过签名来保证signed data分块的完整性
    摘要的计算过程
    • 拆封chunk
      将每个部分拆分成多个大小为1MB大小的chunk,最后的可能小于1MB。分块是为了通过并行计算摘要加快计算速度。
    • 计算chunk摘要
      计算方式:字节0xa5 + 块的长度(字节数)+ 块的内容 计算摘要
    • 计算整体摘要
      计算放肆:字节0x5a + chunk数 + 块的摘要的连接(按块在APK中的顺序)进行计算

    注意:中央目录结尾记录中包含了中央目录的起始偏移量,插入APK签名分块后,中央目录的起始偏移量将发生变化。故在校验签名计算摘要时,需要把中央目录的起始偏移量当做APK签名分块的起始偏移量。

    v2验证过程
    1. 找到APK签名分块并验证以下内容:
      a. APK签名分块的两个大小字段包含相同的值。
      b. ZIP中央目录结尾紧跟在ZIP中央目录记录后面
      c. ZIP中央目录结尾之后没有任何数据
    2. 找到APK签名分块中的第一个APK签名方案v2分块
      存在v2分块则执行第三步,否则使用v1方案验证APK
    3. APK签名方案v2分块中的每个signer执行以下操作:
      a. 从signatures中选择安全系数最高的受支持signature algorithm ID.安全系数排序取决于各个实现/平台版本。
      b. 使用public key并对照signed data验证signatures中对应的signature。
      c. 验证digests和signatures中的签名算法ID列表(有序列表)是否相同,防止删除/添加签名。
      d. 使用签名算法所用的同一种摘要算法计算APK内容的摘要。
      e. 验证计算出的摘要是否与digests中对应的digest相同。
      f. 验证certificates中第一个certificate中对应的digest相同.
    4. 如果找到了至少一个signer,并且对于每个找到的signer,第3步都取得了成功,APK验证将会成功。
    兼容机制

    v2签名机制是在Android 7.0引入的,为了使用v2签名的APK可以在Android 7.0以下版本中安装,应该先用JAR签名对APK进行签名,再用v2方案进行签名。注意先用JAR签名再v2签名,因为JAR签名会修改zip文件数据区和中央目录的内容破坏v2签名的完整性。

    防回滚机制
    • v2签名的APK中同时带有JAR签名,攻击者可能直接删除APK的v2签名吗,使系统只校验JAR签名。为了防止此类攻击,v2方案规定。

    措施:

    v2签名的APK如果还带JAR签名,META-INF/.SF文件的首部必须包含X-Android-APK-Signed属性。

    [图片上传失败...(image-4d0a01-1606978403300)]

    • 攻击者还肯能试图删除APK签名方案v2分块中安全系数较高的签名,使系统验证安全系数较低的签名。

    措施:

    对APK进行签名时使用的签名算法ID列表会储存在signed data分块中。

    v2签名的优势
    • 只需进行一次hash校验,速度快
    • 保证了APK内个文件的完整性

    三、v3签名机制

    3.1 简述

    Android 9.0中加入了v3签名方案,新增了对APK Signature Scheme v3的支持。

    使应用能够在APK更新过程中更改其签名秘钥。

    为了实现轮替,APK必须指示新旧签名秘钥之间的信任级别。为了支持秘钥轮替,APK签名方案从v2更新为v3,以允许使用新旧秘钥。

    v3在APK签名分块中添加了有关受支持的SDK版本和proof-of-rotation结构的信息。

    官方提示:

    注意:在 Android 11 发布之前,建议不要使用 APK 密钥轮替。开发者可以选择针对新安装应用使用 Google Play 的密钥升级。注册了 Play 应用签名的开发者可以通过 Play 管理中心请求升级。

    轮替签名密钥

    轮替签名证书世系或新签名序列的语法如下:

    $ apksigner rotate --in /path/to/existing/lineage \
      --out /path/to/new/file \
      --old-signer --ks old-signer-jks \
      --new-signer --ks new-signer-jks
    
    3.2 v3分块

    v3方案的设计与v2方案非常相似,采用相同的常规格式,并支持相同的签名算法ID、秘钥的大小和EC曲线。

    区别:

    v3方案增添了有关受支持的SDK版本和profo-of-rotation结构的信息。

    Proof-of-rotation和self-trusted-certs结构

    proof-of-rotation结构允许应用轮替其签名证书,而不会使这些证书在与这些应用通信的其他应用上被屏蔽。
    为此应用签名需要包含两个新数据块:

    • 告知第三方应用的签名证书可信(只要其先前证书可信)的断言
    • 应用的旧签名证书(应用本身仍信任这些证书)

    签名部分中的proof-of-rotation属性包含一个单链表,其中每个节点都包含用于为之前版本的应用签名的签名证书。此属性旨在包含概念性proof-of-rotation和self-trusted-old-certs数据结构。
    单链表按照版本排序,最旧的签名证书对应于根节点。
    在构建proof-of-rotation数据结构时,系统会让每个节点中的证书为列表中的下一个证书签名,从而为每个新秘钥提供证据来证明它应该与旧秘钥一样可信。

    格式

    “APK 签名方案 v2 分块”存储在“APK 签名分块”内,ID 为 0xf05368c0

    “APK 签名方案 v3 分块”采用 v2 的格式:

    • 带长度前缀的 signer(带长度前缀)序列:
      • 带长度前缀的 signed data
        • 带长度前缀的 digests(带长度前缀)序列:
          • signature algorithm ID(4 个字节)
          • digest(带长度前缀)
      • 带长度前缀的 X.509 certificates 序列:
        • 带长度前缀的 X.509 certificate(ASN.1 DER 形式)
      • minSDK (uint32) - 如果平台版本低于此数字,应忽略该签名者。
      • maxSDK (uint32) - 如果平台版本高于此数字,应忽略该签名者。
      • 带长度前缀的 additional attributes(带长度前缀)序列:
        • ID (uint32)
        • value(可变长度:附加属性的长度 - 4 个字节)
        • ID - 0x3ba06f8c
        • value - Proof-of-rotation 结构
      • minSDK (uint32) - 签名数据部分中 minSDK 值的副本 - 用于在当前平台不在相应范围内时跳过对此签名的验证。必须与签名数据值匹配。
      • maxSDK (uint32) - 签名数据部分中 maxSDK 值的副本 - 用于在当前平台不在相应范围内时跳过对此签名的验证。必须与签名数据值匹配。
      • 带长度前缀的 signatures(带长度前缀)序列:
        • signature algorithm ID (uint32)
        • signed data 上带长度前缀的 signature
      • 带长度前缀的 public key(SubjectPublicKeyInfo,ASN.1 DER 形式)
    v3验证

    在Android 9.0及更高版本中,可以根据APK签名方案v3、v2或v1验证APK。比较旧的平台会忽略v3签名而尝试验证v2,然后尝试验证v1签名。

    1. 找到APK签名分块并验证一下内容
      a. APK签名分块的两个大小字段包含相同的值
      b. ZIP中央目录结尾紧跟在ZIP中央目录记录后面
      c. ZIP中央目录结尾之后没有任何数据
    2. 找到APK签名分块中的第一个APK 签名方案 v3分块。如果存在v3分块,则继续执行第3步。否则,回退至使用v2方案验证APK。
    3. APK签名方案 v3分块中的每个signer(minSDK和maxSDK范围内)执行以下操作:
      a. 从signatures中选择安全系数最高的受支持signature algorithm ID。安全系数取决于各个实现/平台版本。
      b. 使用public key并对照signed data验证signatures中对应。
      c. 验证签名数据中的最低和最高SDK版本是否与为signer指定的版本匹配。
      d. 验证digestssignatures中的签名算法ID列表是否相同(防止删除/添加签名。)
      e. 使用签名算法所用的同一种摘要算法计算APK内容的摘要。
      f. 验证计算出的摘要是否与digests中对应的digest一致。
      g. 验证certificates中第一个certificate的SubjectPublicKeyInfo是否与public key相同。
      h. 如果signer存在proof-of-rotation属性,验证结构是否有效,以及此singer是否为列表中的最后一个证书。
    4. 如果在当前平台范围内仅找到了一个signer,并且对该signer成功执行第3步,则验证成功。
    v3签名的优势
    • v3签名支持秘钥轮替,可最大限度减少秘钥丢失的影响。
    v4签名

    Android 11 添加了对APK 签名方案 v4的支持。
    此方案会在单独的文件(apk-name.apk.idsing)中生成一种新的签名,但在其他方面与v2和v3类似。没有对APK进行任何更改。此方案支持ADB 增量APK安装,这样会加快APK安装速度。

    优势:

    • 通过APK v4签名,可以使用Android 11中的ADB 增量APK安装快速部署大型APK。

    相关文章

      网友评论

          本文标题:Android签名的问题

          本文链接:https://www.haomeiwen.com/subject/xyuswktx.html