Android数字签名机制

签名机制

Posted by Cc1over on January 16, 2019

Android数字签名机制

数字签名有什么用?

在日常生活中,我们都有过签名表身份的经历,比如:在签署一些协议或者合同的时候,往往需要潇洒的挥上自己的名字,甚至按一下指纹,这都是为了确定行为人的身份,而数字签名是签名的一个分支:基于密码学的签名方式,被数字签名广泛采用的RSA算法就是一种加密算法

数字签名怎么用呢?

在网络发送信息时,存在安全问题,因为在发送者和接收者之间可能存在第三者,截获发送者信息,进行篡改后,再发送给接收者。为了解决这类安全问题,发送者可以对数据进行数字签名,当接收者拿到一堆签名后的数据时,可以对数据进行校验,一旦校验成功,接收者可以信心满满的说:

  • 这些数据一定是某人发送过来的,可以通过其他机构确定发送人的资质
  • 发送者不可抵赖这是自己发送的,一旦接收者一口咬定数据是来源于某位发送者,那发送者只能心服首肯
  • 这些数据一定没有被篡改,否则不会通过校验

这其实就是数字签名的三大特性:可认证性、不可抵赖性和完整性。即便收到被第三者篡改的数据,接收者也可以确定数据不是来源于受信的发送者,而且数据肯定被动过

机制

数字签名是如何保证可认证、不可抵赖和完整性的呢?这得从数字签名的算法说起。数字签名的实现包含三个算法:

  • 密钥生成算法:数字签名采用的是非对称密钥生成算法,即会生成一对密钥:私钥和公钥。用私钥加密的数据,只能用对应的公钥解密。私钥是应该要保护起来,不会泄露给其他人;公钥是完全公开的,会随着加密数据一起在公开网络上传送。

  • 签名算法:给定私钥(private key)和数据(message),可以生成一个签名(signature)。

  • 签名验证算法:给定数据(message)、公钥(public key)和签名(signature),可以解密数据并验证数据的来源和完整性。

密钥有对称(symmetric)和非对称(public)之分。对称密钥只有一个,同时用于加密和解密,就像我们用同一把钥匙开门和锁门,谁拿到钥匙,谁就掌握了房间的使用权。DES和AES这种加密算法采用的是对称密钥,而上文提到的RSA算法采用的是非对称密钥

  • 对待发送的数据明文进行Hash,通常可采用MD5或SHA算法,然后采用私钥对Hash值进行加密,得到签名。将数据明文和签名一同发送出去。为什么要先对原始数据进行Hash后再用私钥加密呢?因为原数据可能比较大,直接使用私钥加密将会非常耗时。
  • 接收数据以后,会经过签名验证,其实就是比较两个Hash值:采用同样的Hash算法对数据明文进行解密,得到一个Hash值;采用公钥对签名进行解密后,得到原始的Hash值。如果两个Hash值相同,则说明数据没有被篡改而且来源可信:
    • 如果用公钥解密成功,则说明公钥与签名的私钥是唯一配对的,即一定是某个私钥的签名,这就保障了来源不可抵赖。
    • 如果数据被篡改,则接收到数据的Hash值与解密后的Hash值不会相同,这就保障了完整性。
    • 接收到的公钥是可以由第三方权威机构(Certificate Authority)认证的,因此接收方可以验证来源是否可靠,这就可以保障来源的可认证性。关于CA认证我们后文再展开。

说了这么多,其中数字签名最神奇的地方就在于密钥对:用私钥加密后的数据只能用对应的公钥解密。 RSA算法的理论根基是欧拉定理,可以参见RSA算法原理介绍

Android中数字签名的使用场景

未签名的apk VS 签名后的apk

对比签名前后apk的文件结构

app-unsigned                    app-signed
├── AndroidManifest.xml         ├── AndroidManifest.xml
├── classes.dex                 ├── classes.dex
├── META-INF                    ├── META-INF
                                 ├── CERT.RSA
                                 ├── CERT.SF
   └── MANIFEST.MF                └── MANIFEST.MF
├── res                         ├── res
└── resources.arsc              └── resources.arsc

由此可见,APK签名前后,只有META-INF目录发生了变化,签名后会更新MANIFEST.MF文件,会增加ANDROIDD.SFANDROIDD.RSA这两个文件

  • CERT.MF是apk包含文件的清单列表,记录了APK中每一个文件的SHA256摘要,前文介绍数字签名的时候说过,签名算法很耗时,因此不是对原文件执行加密算法,而是先生成原文件的摘要,再对摘要进行签名。由此,可以推断出CERT.MF文件的内容就是摘要密文

  • CERT.RSA其实是数字证书,RSA的文件后缀表示证书中包含了一个基于RSA算法生成的公钥

至此,apk签名前后的差异已经分析完毕。签名会在apk中的META-INF/目录下添加证书CERT.RSA和密文CERT.SF,有了这两个文件,就可以对apk进行校验了

Android对apk的签名要求

在Android 系统中,所有安装到系统的应用程序都必有一个数字证书,此数字证书用于标识应用程序的作者和在应用程序之间建立信任关系

Android 系统要求每一个安装进系统的应用程序都是经过数字证书签名的,数字证书的私钥则保存在程序开发者的手中

Android 将数字证书用来标识应用程序的作者和在应用程序之间建立信任关系,不是用来决定最终用户可以安装哪些应用程序

这个数字证书并不需要权威的数字证书签名机构认证(CA),它只是用来让应用程序包自我认证的

同一个开发者的多个程序尽可能使用同一个数字证书,这可以带来以下好处

  • 有利于程序升级,当新版程序和旧版程序的数字证书相同时,Android 系统才会认为这两个程序是同一个程序的不同版本。如果新版程序和旧版程序的数字证书不相同,则Android 系统认为他们是不同的程序,并产生冲突,会要求新程序更改包名

  • 有利于程序的模块化设计和开发。Android 系统允许拥有同一个数字签名的程序运行在一个进程中,Android程序会将他们视为同一个程序。所以开发者可以将自己的程序分模块开发,而用户只需要在需要的时候下载适当的模块

在签名时,需要考虑数字证书的有效期

  • 数字证书的有效期要包含程序的预计生命周期,一旦数字证书失效,持有改数字证书的程序将不能正常升级
  • 如果多个程序使用同一个数字证书,则该数字证书的有效期要包含所有程序的预计生命周期
  • Android Market 强制要求所有应用程序数字证书的有效期要持续到2033 年10 月22 日以后

Android 数字证书包含以下几个要点

  • 所有的应用程序都必须有数字证书,Android 系统不会安装一个没有数字证书的应用程序
  • 如果要正式发布一个Android ,必须使用一个合适的私钥生成的数字证书来给程序签名,而不能使用adt 插件或者ant 工具生成的调试证书来发布
  • 数字证书都是有有效期的,Android 只是在应用程序安装的时候才会检查证书的有效期。如果程序已经安装在系统中,即使证书过期也不会影响程序的正常功能

参考资料:

  • http://duanqz.github.io/2017-09-01-Android-Digital-Signature#12-%E6%9C%BA%E5%88%B6

  • https://blog.csdn.net/axi295309066/article/details/52494832