探究 Android 签名机制和原理 - 腾讯云开发者社区-腾讯云
1. 对发送者的身份认证:由于开发商可能通过使用相同的package name来混淆替换已经安装的程序,以此保证签名不同的包不被替换。
2. 保证信息传输的完成性:签名对于包中的每个文件进行处理,以此确保包中内容不被替换。
3. 防止交易中的抵赖发生,market对软件的要求。
简单来说总体分为以下几个步骤:
1. MANIFEST.MF:一级摘要文件,对Apk中的每个文件做一次算法(数据摘要+Base64编码),保存到MAINFEST.MF
2. CERT.SF二级摘要文件:对MAINFEST.MF整个文件做一次算法(数据摘要+Base64编码),存放到CERT.SF文件的头属性中,在对MAINFEST.MF文件中各个属性块做一次算法(数据摘要+Base64编码),存放到一个属性块中。
3. CERT.RSA 签名文件:对CERT.SF文件做签名,内容存档到CERT.RSA中。最重要,里面保存了公钥、所采用的加密算法 和CERT.SF中的内容的用私钥进行加密之后的值(签名)
其中包含了公钥、加密算法等信息。首先,对前一步生成的 CERT.SF 使用了 SHA256(SHA1)生成了数字摘要并使用了 RSA 加密,接着,利用了开发者私钥进行签名。然后,在安装时使用公钥解密。最后,将其与未加密的摘要信息(MANIFEST.MF文件)进行对比,如果相符,则表明内容没有被修改。
这一步中,即使开发者修改了程序内容,并生成了新的摘要文件,MANIFEST.MF能与内容对应起来,CERT.SF也能与内容对应起来,但是攻击者没有开发者的私钥,所以不能生成正确的签名文件(CERT.RSA)。

通过非对称加密和解密:
加密过程:使用开发者的私钥对摘要信息进行签名
解密过程:使用公钥解密,拿着解密后的值和摘要信息对比,一致则通过校验安装成功,否则安装失败。
那有人会问,我把CERT.RSA中也修改了,把公钥和签名都替换了,重新生成一个CERT.RSA不就行了么?
前面提到CERT.RSA 为签名和数字证书(公钥和辅助的身份信息)组成。
公钥代表了开发者主体身份的唯一性。公钥一样,开发者主体就是一个,公钥不一致肯定是不同的开发主体。
以微信为例,假设你手机上安装过微信,并且你修改微信apk中的个CERT.RSA,替换成了你自己的公钥,和你自己私钥加密后的签名。安装的时候,Android系统检测到,同一个包名,新apk的公钥和已安装的不一致,那么系统就会认为开发者主体不一致,要安装新的apk,需要先把就的apk卸载掉(系统认为公钥不一致,是两个不同的apk,但是两个不同的apk,包名不能一致,需要卸载其中一个)
如果手机上原先没有安装过微信,此时安装修改了签名文件的apk,Android系统是可以校验通过,允许安装的。
那有同学又问了,数字证书中的辅助身份信息,如所有者,签发人,有效期等,这些辅助身份信息和公钥怎样建立一个可信任的匹配关系呢?毕竟我可以伪造数字证书,保留原有的辅助身份信息,用我自己的公钥替换掉原有的公钥信息,神不知鬼不觉。
数字证书的认证,这就涉及到数字证书结构和CA认证机构了。
Android 支持以下三种应用签名方案:


v1 签名有两个地方可以改进:
- 签名校验速度慢 校验过程中需要对apk中所有文件进行摘要计算,在 APK 资源很多、性能较差的机器上签名校验会花费较长时间,导致安装速度慢。
- 完整性保障不够 META-INF 目录用来存放签名,自然此目录本身是不计入签名校验过程的,可以随意在这个目录中添加文件,比如一些快速批量打包方案就选择在这个目录中添加渠道文件。
该方案能够发现对 APK 受保护部分进行的所有更改,从而有助于加快验证速度并增强完整性保证。v2 签名机制不存在解压原始数据,签名校验时间显著减少,因此安装时间也相应减少。同时,它是基于 APK 的二进制内存做的签名信息(APK Signing Block 签名块本身不参与加密校验),因此打包后改变 APK 的其他三部分的任何字节都会导致签名校验不通过。这也说明了,zipalign 是要在 apksigner 之前的。
把 APK 按照 1M 大小分割,分别计算这些分段的摘要,最后把这些分段的摘要在进行计算得到最终的摘要也就是 APK 的摘要。然后将 APK 的摘要 + 数字证书 + 其他属性生成签名数据写入到 APK Signing Block 区块。
