引言
在Android开发的世界中,APK的签名机制是确保应用安全性的关键环节。随着技术的不断进步,Android签名机制也经历了从v1到v3的演进。本文将带你深入了解Android签名机制的演变过程,揭示每个版本背后的技术细节,并探讨它们对开发者和用户的影响。
一、签名机制
1、什么是Android签名?
在Android生态中,APK签名机制是确保应用安全性的重要环节。它不仅保障了应用来源的真实性,还防止了APK文件在传输过程中被篡改。Android系统要求每个应用程序都必须经过数字签名,这是一种使用密钥对(包含公钥和私钥)对应用程序进行加密和验证的方式。
2、签名机制的主要目的
-
确保应用程序的完整性
当用户从任何来源(如Google Play商店或第三方网站)下载应用程序时,Android系统会使用应用程序的证书对应的公钥来验证应用程序的签名。如果签名验证通过,则表明应用程序在传输过程中没有被篡改或损坏,确保了应用程序的完整性。
-
建立应用程序的信任关系
Android系统使用应用程序的签名来识别应用程序的开发者身份。如果同一个开发者发布了一个新版本的应用程序,Android系统会检查新版本的签名是否与之前版本的签名相同。只有签名相同,Android系统才会允许新版本应用程序访问之前版本应用程序的数据和资源,从而建立了应用程序之间的信任关系。
-
保护应用程序的权限和数据
Android系统使用签名来控制应用程序之间的权限和数据访问。例如,如果一个应用程序需要访问另一个应用程序的组件(如Activity、Service或BroadcastReceiver),则两个应用程序必须由同一个开发者签名,否则将无法访问。这种机制可以防止恶意应用程序访问其他应用程序的敏感数据或资源。
举个例子,假设你是Android应用程序开发者,你需要发布一个新的应用程序。
在开发过程中,你需要生成一个密钥对,使用私钥对应用程序进行签名。然后,你可以将公钥嵌入到应用程序的元数据中,并将签名后的应用程序发布到Google Play商店或其他渠道。
当用户下载并安装你的应用程序时,Android系统会使用嵌入在应用程序中的公钥来验证应用程序的签名。如果签名验证通过,则表明应用程序来自可信任的来源,没有被篡改过,系统会允许应用程序安装和运行。
如果你以后需要发布应用程序的新版本,你必须使用相同的私钥对新版本进行签名。这样,Android系统就会识别出新版本和旧版本来自同一个开发者,并允许新版本访问旧版本的数据和资源。
二、签名机制的核心概念
1、消息摘要
消息摘要(Message Digest)是一种通过单向散列算法对任意长度的数据进行计算并产生固定长度的小型摘要信息(又称哈希值或指纹)的技术。
(1)、消息摘要主要特点
-
压缩性:无论输入的数据有多大,计算出来的消息摘要的长度都是固定的,通常为128位或更长。
-
易计算:给定需要计算摘要的数据,非常容易计算出消息摘要。
-
隐行性:相同的输入必定得到相同的输出,但反过来,由输出极其困难推导出输入值。
-
抗碰撞:理论上不可能找到两个不同的输入计算出相同的消息摘要。
常见的消息摘要算法有:MD5、SHA-1、SHA-256等。以MD5为例,它会对任意长度的输入数据执行一系列复杂的操作,最终生成一个128位(16字节)的散列值。这个散列值就是该输入数据的唯一"指纹"。
(2)、消息摘要应用场景
-
数据完整性验证
通过对原始数据计算出摘要,传输时只需传输摘要。接收方重新计算摘要并与传输的摘要进行比对,可验证数据在传输过程中是否遭到篡改。如软件下载的MD5/SHA-1校验。
-
数字签名
发送方先对原始数据计算消息摘要,再使用自己的私钥对摘要加密,形成数字签名附加在原始数据后发送。接收方使用发送方的公钥解密签名,并重新计算原始数据的摘要与解密后的摘要进行比对,以验证数据的完整性和发送方身份。
-
信息认证
可使用消息摘要作为口令、证书等的内容,再与其他信息结合来认证用户或实体身份。
-
数据去重
在处理海量数据时,利用消息摘要可方便地对重复数据进行判断和去重处理。
-
散列表
消息摘要常被用来优化存储和查找,作为键值存储结构的关键字段。
2、数字签名
数字签名(Digital Signature)是一种利用加密技术在数字信息上附加一个标记,以实现信息发送者身份的可靠性、数据完整性和防止抵赖性的密码技术。
(1)、数字签名特点
-
真实性认证
数字签名使用了发送者的私钥进行签名,只有拥有对应私钥的发送者才能产生有效的数字签名。接收方可使用发送者的公钥对签名进行验证,以确认信息确实来自声称的发送者。
-
不可抵赖性
发送者在发送信息前先对信息签名,一旦签名的信息被发送,发送者就无法抵赖曾经发送过这个消息。
-
完整性
数字签名是在原始数据上做运算得到的,任何对原始数据的修改都会使签名失效。因此,数字签名能有效防止信息在传输过程中被篡改。
- 不可伪造
理论上,由于采用了单向散列函数和发送者私钥的双重保护,数字签名是不可能被伪造的。
(2)、数字签名的生成过程
- 使用摘要算法(如MD5、SHA-1等)计算原始数据的消息摘要
- 使用发送者的私钥对消息摘要进行加密,生成数字签名
- 将原始数据和数字签名一并发送
(3)、验证数字签名过程
- 使用同样的摘要算法计算收到原始数据的消息摘要
- 使用发送者的公钥对数字签名进行解密,获得原始的消息摘要
- 比较两个消息摘要是否相同,若相同则验证通过
常见的数字签名算法有RSA、DSA等,它们基于复杂的数论和离散对数问题,具有非常高的计算复杂度,从理论上保证了签名的安全性。
数字签名被广泛应用于电子商务、网上银行、软件分发、电子合同、电子政务等领域,是构建信任机制、保证信息安全的重要手段。
3、数字证书
数字证书(Digital Certificate)是一种用于加密和解密的电子文件,它遵循国际标准X.509,用于确认公钥实际属于某个人或组织。
数字证书最关键的作用是在网络通信中确认对方身份的合法性,建立加密连接的信任基础。
数字证书通过CA机构的数字签名,解决了公钥的安全可信问题,保证了公钥的持有者身份。
(1)、数字证书包含信息
-
证书版本号:标识证书所使用的X.509标准版本。
-
证书序列号:证书的唯一标识符号。
-
签名算法:签发证书时所使用的签名算法,如SHA256withRSA。
-
签发者:签发此证书的证书颁发机构(CA)的信息。
-
有效期限:证书的有效期,包括生效日期和失效日期。
-
主题信息:持有此证书实体的信息,如组织名称、域名等。
-
公钥信息:证书持有者的公钥数据,用于加密或验证数字签名。
-
扩展信息:可选的附加信息,如密钥使用范围、证书吊销列表分发点等。
-
数字签名:由证书颁发机构使用其私钥对整个证书进行签名后的数字签名值。
(2)、数字证书的生成和使用过程
- 证书申请者向权威的证书颁发机构(CA)提交公钥、个人信息和申请证书材料。
- CA按照严格的身份审核流程,验证申请者的身份合法有效后。
- CA使用自身的私钥,对申请者的证书信息进行数字签名,并将证书文件返回给申请者。
- 申请者收到数字证书后,即可使用其中的公钥进行加密和解密操作。
- 任何需要验证申请者身份的第三方,只需获取证书对应的CA的公钥,就能验证证书上的数字签名,确认公钥的所有权。
(3)、数字证书应用场景
- HTTPS网站服务,确保网站身份合法有效
- 移动应用程序,验证APP签名身份
- 电子邮件签名,防止邮件伪造
- 文件签名,确保文件的完整性和发送者身份
- 无线网络接入,验证无线接入点的合法性
- 虚拟专网VPN,实现客户端到服务器的加密通信
三、APK签名方案v1
1、APK签名方案v1原理
v1签名使用的是SHA-1算法对整个APK进行摘要计算,然后使用开发者私钥对该摘要进行数字签名。
签名后的数据将被储存在APK的META-INF/CERT.SF和META-INF/CERT.RSA文件中。
(1)、MANIFEST.MF
该文件中保存的内容其实就是逐一遍历 APK 中的所有条目,如果是目录就跳过,如果是一个文件,就用 SHA1(或者 SHA256)消息摘要算法提取出该文件的摘要然后进行 BASE64 编码后,作为「SHA1-Digest」属性的值写入到 MANIFEST.MF 文件中的一个块中。该块有一个「Name」属性, 其值就是该文件在 APK 包中的路径。
(2)、CERT.SF
- SHA1-Digest-Manifest-Main-Attributes:对 MANIFEST.MF 头部的块做 SHA1(或者SHA256)后再用 Base64 编码
- SHA1-Digest-Manifest:对整个 MANIFEST.MF 文件做 SHA1(或者 SHA256)后再用 Base64 编码
- SHA1-Digest:对 MANIFEST.MF 的各个条目做 SHA1(或者 SHA256)后再用 Base64 编码
(3)、CERT.RSA
这里会把之前生成的 CERT.SF 文件,用私钥计算出签名, 然后将签名以及包含公钥信息的数字证书一同写入 CERT.RSA 中保存。
这里要注意的是,Android APK 中的 CERT.RSA 证书是自签名的,并不需要这个证书是第三方权威机构发布或者认证的,用户可以在本地机器自行生成这个自签名证书。Android 目前不对应用证书进行 CA 认证。
这里我们看到的都是二进制文件,因为 RSA 文件加密了,需要用 openssl 命令才能查看其内容:
$ openssl pkcs7 -inform DER -in /Sample-release_new/original/META-INF/CERT.RSA -text -noout -print_certs
签名具体过程:
- 计算APK的SHA-1摘要值digest
- 使用开发者私钥对digest进行签名,生成数字签名sig
- 将sig存储在CERT.RSA文件中
- 生成包含APK的digest描述及其他元数据的CERT.SF文件
- 对CERT.SF文件计算SHA-1摘要digest2
- 使用开发者私钥对digest2签名,存储到CERT.SF中
签名校验过程:
签名验证是发生在 APK 的安装过程中,一共分为三步:
-
第一步,检查 APK 中包含的所有文件,对应的摘要值与 MANIFEST.MF 文件中记录的值一致。
-
第二步,使用证书文件(RSA 文件)检验签名文件(SF 文件)没有被修改过。
-
第三步,使用签名文件(SF 文件)检验 MF 文件没有被修改过。
2、使用APK签名v1的完整示例
(1)、生成密钥对
使用keytool工具生成密钥对,别名为mykey,有效期为10000天:
keytool -genkey -v -keystore mykey.keystore -alias mykey -keyalg RSA -keysize 2048 -validity 10000
(2)、对APK进行对齐
使用zipalign工具对APK进行对齐优化:
复制
zipalign 4 myapp.apk myapp-aligned.apk
(3)、获取待签名APK的摘要值
使用apkutil工具计算待签名APK的摘要值:
apkutil digest myapp-aligned.apk
Digest of myapp-aligned.apk:
SHA-1: A0:EA:B8:12.....
(4)、使用密钥库签名APK
使用apksigner工具对APK进行签名:
apksigner sign --ks mykey.keystore --ks-key-alias mykey myapp-aligned.apk
输入密钥库密码后,APK将被签名,生成myapp-aligned-signed.apk文件。
(5)、验证签名
使用apksigner工具验证签名:
apksigner verify --verbose myapp-aligned-signed.apk
输出显示APK签名合法,说明签名成功。
这样就完成了使用v1签名方案对APK进行签名的全过程。
需要注意的是,从Android 9.0开始,APK需要同时使用v1和v2签名方案。使用v2签名方案可以提高签名效率和安全性。开发者可以使用Android SDK的apksigner工具同时进行v1和v2签名。
四、APK签名方案v2
Android APK签名方案v2是Google在Android 7.0中引入的新签名方案,旨在提高签名的效率和安全性。它主要解决了v1方案中存在的一些问题,如签名数据过大、校验效率低下等。
1、APK签名方案v2原理
v2签名使用更高强度的SHA-256算法和先进的APK Signature Scheme v2签名方案。
v2 签名模式在原先 APK 块中增加了一个新的块(签名块),新的块存储了签名,摘要,签名算法,证书链,额外属性等信息,这个块有特定的格式。
为了保护 APK 内容,整个 APK(ZIP 文件格式)被分为以下 4 个区块:
-
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 的修改都逃不过新的应用签名方案的检查。
主要特点:
- 使用更高强度的SHA-256代替SHA-1
- 只对APK中的代码和资源进行签名,而不是整个APK文件
- 引入APK Signature Scheme v2,对每个文件单独签名并存储签名数据
- 支持使用多个签名密钥对APK签名
签名过程:
-
遍历APK中的所有内容,计算SHA-256摘要值
-
使用开发者的私钥对每个文件摘要进行签名
-
将所有文件签名保存在APK的META-INF/hashValue文件中
-
生成证书列表,存储在APK的META-INF/hashValue.sf文件中
-
生成APK Signature Block,包含证书链、签名数据,存储在APK的META-INF/hashValue.rsa文件中
签名校验过程:
我们来看v2签名的校验过程,整体大概流程如下图所示:
其中 v2 签名机制是在 Android 7.0 以及以上版本才支持。
因此对于 Android 7.0 以及以上版本,在安装过程中,如果发现有 v2 签名块,则必须走 v2 签名机制,不能绕过;否则降级走 v1 签名机制。 v1 和 v2 签名机制是可以同时存在的,其中对于 v1 和 v2 版本同时存在的时候,v1 版本的 META_INF 的 .SF
文件属性当中有一个 X-Android-APK-Signed
属性:
X-Android-APK-Signed: 2
因此如果想绕过 v2 走 v1 校验是不行的。
2、使用APK签名v2的完整示例
(1)、生成密钥对
keytool -genkey -v -keystore mykey.keystore -alias mykey -keyalg RSA -keysize 2048 -validity 10000
(2)、使用zipalign优化APK文件
zipalign 4 myapp.apk myapp-aligned.apk
(3)、使用apksigner对APK进行v2签名
apksigner sign --ks mykey.keystore --ks-key-alias mykey --v2-signing-enabled true myapp-aligned.apk
输入密钥库密码后,apksigner将会生成已签名的APK文件myapp-aligned-signed.apk。
(4)、验证APK签名(可选)
apksigner verify --verbose myapp-aligned-signed.apk
输出显示APK使用的是v2签名方案,并且签名合法。
这样就完成了v2签名方案对APK的签名操作。我们可以看到相比v1方案,v2签名更加高效和安全,签名数据也更小。
需要注意的是,从Android 9.0开始,Google要求所有上架Google Play的新APK必须同时使用v1和v2签名方案进行签名。
我们可以使用如下:
apksigner sign --ks mykey.keystore --ks-key-alias mykey --v1-signing-enabled true --v2-signing-enabled true myapp-aligned.apk
这将生成一个同时包含v1和v2签名的APK文件,可以在所有Android版本上安装和运行。
五、APK签名方案v3
Android APK签名方案v3是Google在Android 11中引入的最新签名方案,主要目的是提高签名的安全性和可靠性。相比之前的签名方案,v3签名引入了一些重大改变,如引入Android KeyStore系统以增强密钥安全性、支持对签名使用压缩等。下面将详细介绍APK签名v3的原理和使用案例。
1、APK签名方案v3原理
(1)、v3签名的主要特性
-
使用Android KeyStore系统存储和管理私钥,增强密钥安全性。
-
支持使用压缩算法(如gzip)对签名数据进行压缩,减小APK大小。
-
支持签名时向APK添加新的签名方案,但保留之前版本的签名数据。
-
签名时支持附加描述信息(attribution)。
(2)、签名过程
- 开发者生成密钥对,并将私钥安全存储在Android KeyStore系统中。
- 遍历APK内容,计算SHA-256或SHA-512摘要值。
- 使用私钥对每个文件摘要进行签名。
- 将签名数据压缩后存储在APK的新增的APK Signature Block文件中。
- 可选地添加签名者的描述信息(attribution)。
(3)、签名校验过程
需要注意的是,对于覆盖安装的情况,签名校验只支持升级,而不支持降级。也就是说设备上安装了一个使用 v1 签名的 APK,可以使用 v2 签名的 APK 进行覆盖安装,反之则不允许。
(3)、使用APK签名v3的完整示例
- 生成密钥对并保存到Android KeyStore
cmd: keytool --genkeypair --v --keystore ~/.android/debug.keystore --alias androiddebugkey --keyalg RSA --keysize 2048 --validity 10000
- 使用zipalign优化APK
zipalign 4 myapp.apk myapp-aligned.apk
- 使用apksigner进行v3签名
从Android 11开始,apksigner工具默认使用v3签名方案
apksigner sign --ks ~/.android/debug.keystore --ks-key-alias androiddebugkey myapp-aligned.apk
输入密钥库密码后,将生成已签名的APK: myapp-aligned-signed.apk
- 验证APK签名
apksigner verify --verbose myapp-aligned-signed.apk
输出将显示签名使用了v3方案,并且合法有效。
以上就是使用v3签名APK的完整过程。
值得注意的是:
- 对于Android 11及更高版本,Google Play要求新APK必须使用v3签名方案。
- 对于Android 9至10版本,新APK需同时使用v2和v3签名。可以使用参数
--v2-signing-enabled true
启用v2签名。 - 对于Android 8及以下版本,新APK必须使用v1和v2签名,使用参数
--v1-signing-enabled true
启用v1签名。
通过并存不同版本的签名数据,Google保证了APK在所有Android版本上的兼容性。总的来说,v3签名进一步增强了签名的安全性和可靠性,为Android系统的应用程序分发提供了更好的保护。
结语
签名机制的演进为Android应用的安全性提供了坚实的基础,但随着技术的发展,未来是否还会出现新的签名方案?现有的机制又将如何适应不断变化的安全需求?让我们拭目以待。