APK签名原理解析

目录

  1. 相关概念
  2. 签名原理
  3. 验证过程
  4. 参考

相关概念

  • Message Digest(数字摘要)
    将任意长度的消息变成固定长度的短消息,它类似于一个自变量是消息的函数,也就是Hash函数。数字摘要是采用单项Hash函数将需要加密的明文“摘要”成一串固定长度(128位)的密文这一串密文又称为数字指纹,它有固定的长度,而且不同的明文摘要成密文,其结果总是不同的,而同样的明文其摘要必定一致。
  • Signature(数字签名)
    数字签名是非对称密钥加密技术与数字摘要技术的应用。将信息摘要用发送者的私钥加密,与原文一起传送给接收者。接收者只有用发送者的公钥才能解密被加密的信息摘要,然后接收者用相同的Hash函数对收到的原文产生一个信息摘要,与解密的信息摘要做比对。如果相同,则说明收到的信息是完整的,在传输过程中没有被修改;不同则说明信息被修改过,因此数字签名能保证信息的完整性。并且由于只有发送者才有加密摘要的私钥,所以我们可以确定信息一定是发送者发送的(发送者的身份认证)。
  • Certification(数字证书)
    数字证书是一个经证书授权中心数字签名的包含公开密钥拥有者信息以及公开密钥的文件。最简单的证书包含一个公开密钥、名称以及证书授权中心的数字签名。数字证书还有一个重要的特征就是只在特定的时间段内有效。
  • Certification Authority(CA机构)
    受信任的第三方,承担公钥体系中公钥的合法性检验的责任
  • 根证书
    是未被签名的公钥证书或自签名的证书;是CA认证中心给自己颁发的证书,是信任链的起始点。安装根证书意味着对这个CA认证中心的信任。用户在使用自己的数字证书之前必须先下载根证书。
  • 数字证书格式(普遍采用X.509V3标准)
  • 数字证书存储格式
    带有私钥的证书由Public Key Cryptography Standards #12(PKCS#12)标准定义,包含了公钥和私钥的二进制格式的证书形式,以pfx作为证书文件后缀名。
    二进制编码的证书中没有私钥,DER编码二进制格式的证书文件,以cer作为证书文件后缀名。
    Base64编码的证书中没有私钥,BASE64编码格式的证书文件,以cer作为证书文件后缀名。

签名原理

  • 签名目的
    为了保证每个应用程序开发商合法ID,防止部分开放商可能通过使用相同的Package Name来混淆替换已经安装的程序,我们需要对我们发布的APK文件进行唯一签名,保证我们每次发布的版本的一致性(如自动更新不会因为版本不一致而无法安装);也就是说Android不允许有包名相同的应用同时存在手机中;同时,在权限检查方面,对于申请权限的 protection level 为 signature 或者 signatureOrSystem 的,会检查权限申请者和权限声明者的证书是否是一致的。
    Android要求所有已安装的应用程序都使用数字证书做签名,数字证书的私钥由应用开发者持有。证书不需要证书认证中心签名,是自签名证书!没有正确签名的应用,Android系统不会安装或运行;数字证书是有有效期的,应该比所有用这个证书签名的应用寿命长,不然一旦证书失效,持有数字证书的程序无法正常升级;Android Market要求所有应用数字证书有效期持续到2033年10月22日以后。
    Keytool是用来管理私钥仓库(keystore)和与之相关X.509证书链,是个密钥和证书管理工具。它使用户能够管理自己的公钥/私钥对及相关证书,用于(通过数字签名)自我认证(用户向别的用户/服务认证自己)或数据完整性以及认证服务,通常存在keystore文件中。
  • Debug签名
    Eclipse ADT 或者 android studio调试时,使用debug签名,默认路径是 ~/.android/debug。keystore,Keystore password 和 Key password 都为 android,让我看看这个debug。keystore详细信息,输入keytool -list -keystore debug.keystore 其中,JKS是默认格式,其他有JCEKS(存储对称密钥),PKCS#12(通用格式,RSA公司标准,微软和Java都支持),JKS只能存储非对称密钥(私钥+X509公钥证书)。
  • Android系统签名
    谷歌CTS(兼容性测试)需要系统签名。个人理解就是厂商为自己硬件定制的Android系统必须通过CTS测试才能保证开发的Android应用都能在上面运行,才能申请Android Market。定制的系统必须要进行系统签名,防止被别人盗用。源码提供make_key脚本调用openssh生成私钥和证书两个文件,然后使用Android源码提供signapk进行签名,主要是ROM移植时使用。
  • APK签名
    keytool生成签名文件keystore,默认打包脚本(sdk\tools\ant\build.xml)调用signapk进行签名,signapk源码在附件中提供,签名过程主要涉及三个文件,MANIFEST.MF,CERT.SF和CERT.RSA,存放在META-INF文件夹中。
    MANIFEST.MF:所有文件与其SHA1摘要值,但是不会包含META-INF中的三个文件。 CERT.SF:整个MANIFEST.MF的SHA1摘要值;针对MANIFEST.MF文件中每一个文件三行数据(空行算一行)生成其对应的SHA1-Digest。 CERT.RSA:格式为PKCS7的数字证书,其中证书发行者对证书的签名是对CERT.SF文件的数字签名,所以是自签名证书。

验证过程

根据Oracle官方关于jarsigner文档,分三步:

  1. 验证CERT.SF文件(使用公钥拿到CERT.SF的摘要与当前CERT.SF文件的摘要进行比对)。
  2. 验证CERT.SF中每一项是否与MANIFEST对应项一致(其中CERT.SF文件中manifest项的SHA1值不要求一样,其余每一项要求一样)。
  3. 针对CERT.SF每一项,读取对应文件,计算其digest与MANIFEST对应项进行对比。如果攻击者修改程序,没有私钥无法生成CERT.RSA中的数字签名,所以私钥一定要保管好!CERT.RSA和CERT.SF文件的后缀名不能变,名字可以随意起,但必须相同。

参考

  1. http://baike.baidu.com/view/16501.htm
  2. http://docs.oracle.com/javase/8/docs/technotes/tools/windows/jarsigner.html
  3. https://developer.android.com/tools/publishing/app-signing.html