为什么要签名?
确保Apk来源的真实性。
确保Apk没有被第三方篡改。
什么是签名?
在Apk中写入一个“指纹”。指纹写入以后,Apk中有任何修改,都会导致这个指纹无效,Android系统在安装Apk进行签名校验时就会不通过,从而保证了安全性。
apk组成
dex:最终生成的Dalvik字节码。
res:存放资源文件的目录。
asserts:额外建立的资源文件夹。
lib:如果存在的话,存放的是ndk编出来的so库。
META-INF:存放签名信息
MANIFEST.MF(清单文件):其中每一个资源文件都有一个SHA-256-Digest签名,MANIFEST.MF文件的SHA256(SHA1)并base64编码的结果即为CERT.SF中的SHA256-Digest-Manifest值。
CERT.SF(待签名文件):除了开头处定义的SHA256(SHA1)-Digest-Manifest值,后面几项的值是对MANIFEST.MF文件中的每项再次SHA256并base64编码后的值。
CERT.RSA(签名结果文件):其中包含了公钥、加密算法等信息。首先对前一步生成的MANIFEST.MF使用了SHA256(SHA1)-RSA算法,用开发者私钥签名,然后在安装时使用公钥解密。最后,将其与未加密的摘要信息(MANIFEST.MF文件)进行对比,如果相符,则表明内容没有被修改。
androidManifest:程序的全局清单配置文件。
resources.arsc:编译后的二进制资源文件。
数字摘要
对一个任意长度的数据,通过一个Hash算法计算后,都可以得到一个固定长度的二进制数据,这个数据就称为“摘要”。
补充:
散列算法的基础原理:将数据(如一段文字)运算变为另一固定长度值。
SHA-1:在密码学中,SHA-1(安全散列算法1)是一种加密散列函数,它接受输入并产生一个160 位(20 字节)散列值,称为消息摘要 。
MD5:MD5消息摘要算法(英语:MD5 Message-Digest Algorithm),一种被广泛使用的密码散列函数,可以产生出一个128位(16字节)的散列值(hash value),用于确保信息传输完整一致。
SHA-2:名称来自于安全散列算法2(英语:Secure Hash Algorithm 2)的缩写,一种密码散列函数算法标准,其下又可再分为六个不同的算法标准,包括了:SHA-224、SHA-256、SHA-384、SHA-512、SHA-512/224、SHA-512/256。
特征:
唯一性
固定长度:比较常用的Hash算法有MD5和SHA1,MD5的长度是128拉,SHA1的长度是160位。
不可逆性
签名和校验的主要过程
签名就是在摘要的基础上再进行一次加密,对摘要加密后的数据就可以当作数字签名。
签名过程:
1、计算摘要:通过Hash算法提取出原始数据的摘要。
2、计算签名:再通过基于密钥(私钥)的非对称加密算法对提取出的摘要进行加密,加密后的数据就是签名信息。
3、写入签名:将签名信息写入原始数据的签名区块内。
校验过程:
1、首先用同样的Hash算法从接收到的数据中提取出摘要。
2、解密签名:使用发送方的公钥对数字签名进行解密,解密出原始摘要。
3、比较摘要:如果解密后的数据和提取的摘要一致,则校验通过;如果数据被第三方篡改过,解密后的数据和摘要将会不一致,则校验不通过。
数字证书
如何保证公钥的可靠性呢?答案是数字证书,数字证书是身份认证机构(Certificate Authority)颁发的,包含了以下信息:
证书颁发机构
证书颁发机构签名
证书绑定的服务器域名
证书版本、有效期
签名使用的加密算法(非对称算法,如RSA)
公钥等
接收方收到消息后,先向CA验证证书的合法性,再进行签名校验。
注意:Apk的证书通常是自签名的,也就是由开发者自己制作,没有向CA机构申请。Android在安装Apk时并没有校验证书本身的合法性,只是从证书中提取公钥和加密算法,这也正是对第三方Apk重新签名后,还能够继续在没有安装这个Apk的系统中继续安装的原因。
keystore和证书格式
keystore文件中包含了私钥、公钥和数字证书。根据编码不同,keystore文件分为很多种,Android使用的是Java标准keystore格式JKS(Java Key Storage),所以通过Android Studio导出的keystore文件是以.jks结尾的。
jarsigner和apksigner的区别
Android提供了两种对Apk的签名方式,一种是基于JAR的签名方式,另一种是基于Apk的签名方式,它们的主要区别在于使用的签名文件不一样:jarsigner使用keystore文件进行签名;apksigner除了支持使用keystore文件进行签名外,还支持直接指定pem证书文件和私钥进行签名。
在签名时,除了要指定keystore文件和密码外,也要指定alias和key的密码,这是为什么呢?
keystore是一个密钥库,也就是说它可以存储多对密钥和证书,keystore的密码是用于保护keystore本身的,一对密钥和证书是通过alias来区分的。所以jarsigner是支持使用多个证书对Apk进行签名的,apksigner也同样支持。
Android Apk V1 签名原理
1、解析出 CERT.RSA 文件中的证书、公钥,解密 CERT.RSA 中的加密数据。
2、解密结果和 CERT.SF 的指纹进行对比,保证 CERT.SF 没有被篡改。
3、而 CERT.SF 中的内容再和 MANIFEST.MF 指纹对比,保证 MANIFEST.MF 文件没有被篡改。
4、MANIFEST.MF 中的内容和 APK 所有文件指纹逐一对比,保证 APK 没有被篡改。