大家好,又见面了,我是你们的朋友全栈君。
非对称加密算法
非对称加密算法需要两个密钥:公开密钥(简称公钥)和私有密钥(简称私钥)。公钥与私钥是一对,如果用公钥对数据进行加密,只有用对应的私钥才能解密;如果用私钥对数据进行加密,那么只有用对应的公钥才能解密。因为加密和解密使用的是两个不同的密钥,所以这种算法叫作非对称加密算法。
非对称加密算法是数字签名和数字证书的基础,大家非常熟悉的RSA就是非对称加密算法的一种实现。
消息摘要算法
消息摘要算法(Message Digest Algorithm)是一种能产生特殊输出格式的算法,其原理是根据一定的运算规则对原始数据进行某种形式的信息提取,被提取出的信息就被称作原始数据的消息摘要。著名的摘要算法有RSA公司的MD5算法和SHA-1算法及其大量的变体。
数字签名及数字证书
数字证书
1.证书发布机构
2.证书的有效期3
3.消息发送方的公钥
4.证书的所有者
5.数字签名所使用的算法
6.数字签名
APK签名前
APK签名后
META-INF文件夹
其实,在Android的源代码里包含了一个工具,可以对apk文件进行签名,具体的代码位置在buildtoolssignapk目录下,通过分析其中的SignApk.Java文件,可以大致了解签名的过程。其流程大致有如下几步:
1)打开待签名的apk文件(由于apk其实是一个用zip压缩的文件,其实就是用zip解压整个apk文件),逐一遍历里面的所有条目,如果是目录就跳过,如果是一个文件,就用SHA1(或者SHA256)消息摘要算法提取出该文件的摘要然后进行BASE64编码后,作为“SHA1-Digest”属性的值写入到MANIFEST.MF文件中的一个块中。该块有一个“Name”属性,其值就是该文件在apk包中的路径。
2)计算这个MANIFEST.MF文件的整体SHA1值,再经过BASE64编码后,记录在CERT.SF主属性块(在文件头上)的“SHA1-Digest-Manifest”属性值值下。
然后,再逐条计算MANIFEST.MF文件中每一个块的SHA1,并经过BASE64编码后,记录在CERT.SF中的同名块中,属性的名字是“SHA1-Digest”。
3)把之前生成的 CERT.SF文件, 用私钥计算出签名, 然后将签名以及包含公钥信息的数字证书一同写入 CERT.RSA 中保存。CERT.RSA是一个满足PKCS7格式的文件,可以通过openssl工具来查看签名证书的信息。在Ubuntu或者在Windows上使用Cygwin,敲入以下命令:
[plain] view plain copy
- openssl pkcs7 -inform DER -in CERT.RSA -noout -print_certs –text
可以得到如下输出:
下面我们来看看,如果apk文件被篡改后会发生什么。
首先,如果你改变了apk包中的任何文件,那么在apk安装校验时,改变后的文件摘要信息与MANIFEST.MF的检验信息不同,于是验证失败,程序就不能成功安装。
其次,如果你对更改的过的文件相应的算出新的摘要值,然后更改MANIFEST.MF文件里面对应的属性值,那么必定与CERT.SF文件中算出的摘要值不一样,照样验证失败。
最后,如果你还不死心,继续计算MANIFEST.MF的摘要值,相应的更改CERT.SF里面的值,那么数字签名值必定与CERT.RSA文件中记录的不一样,还是失败。
那么能不能继续伪造数字签名呢?不可能,因为没有数字证书对应的私钥。
所以,如果要重新打包后的应用程序能再Android设备上安装,必须对其进行重签名。
我们还是用前面的例子分析,假设签名后,apk文件中多了一个META-INF目录,里面有三个文件,分别是MANIFEST.MF、CERT.SF和CERT.RSA:
通过前面的分析,我们可以知道,MANIFEST.MF中记录的是apk中所有文件的摘要值;CERT.SF中记录的是对MANIFEST.MF的摘要值,包括整个文件的摘要,还有文件中每一项的摘要;而CERT.RSA中记录的是对CERT.SF文件的签名,以及签名的公钥。
大家知道,Android平台上所有应用程序安装都是由 PackageManangerService(代码位于 frameworksbaseservicescorejavacomandroidserverpmPackageManagerService.java)来管理的,Android的安装流程非常复杂,与签名验证相关的步骤位于 installPackageLI函数中:
总结
1)Android应用程序签名只是用来解决发布的应用不被别人篡改的,其并不会对应用程序本身进行加密,这点不同于Windows Phone和iOS。
2)Android并不要求所有应用程序的签名证书都由可信任CA的根证书签名,通过这点保证了其生态系统的开放性,所有人都可以用自己生成的证书对应用程序签名。
3)如果想修改一个已经发布的应用程序,哪怕是修改一张图片,都必须对其进行重新签名。但是,签原始应用的私钥一般是拿不到的(肯定在原始应用程序开发者的手上,且不可能公布出去),所以只能用另外一组公私钥对,生成一个新的证书,对重打包的应用进行签名。所以重打包的apk中所带证书的公钥肯定和原始应用不一样。同时,在手机上如果想安装一个应用程序,应用程序安装器会先检查相同包名的应用是否已经被安装过,如果已经安装过,会继续判断已经安装的应用和将要安装的应用,其所携带的数字证书中的公钥是否一致。如果相同,则继续安装;而如果不同,则会提示用户先卸载前面已安装的应用。
到这里,apk安装时的签名验证过程都已经分析完了,来总结一下:
- 所有有关apk文件的签名验证工作都是在JarVerifier里面做的,一共分成三步;
- JarVeirifer.verifyCertificate主要做了两步。首先,使用证书文件(在META-INF目录下,以.DSA、.RSA或者.EC结尾的文件)检验签名文件(在META-INF目录下,和证书文件同名,但扩展名为.SF的文件)是没有被修改过的。然后,使用签名文件,检验MANIFEST.MF文件中的内容也没有被篡改过;
- JarVerifier.VerifierEntry.verify做了最后一步验证,即保证apk文件中包含的所有文件,对应的摘要值与MANIFEST.MF文件中记录的一致。
发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/139719.html原文链接:https://javaforall.cn