Android 签名介绍
所有的Android应用程序要想在设备上安装,必须经过签名,不管是Debug版本还是Release版本。下面分别介绍这两种模式。
- Debug模式
这个模式的签名过程由系统自动完成。因为采用默认的keystore,用户不需要特地输入密码等信息。签名所用工具Keytool和Jarsinger均由JDK提供,因此需要保证JAVA_HOME环境变量的正确性。
默认条件下,系统会存放一个debug.keystore签名文件用于对Debug模式下的应用进行签名。存放debug.keystore文件的路径根据平台的不同会有差异。
- Linux和OS X 在
~.android/
- Windows XP 在
C:\Documents and Settings\<user>\.android\
- Windows 7 在
C:\Users\<user>\.android\
利用keytool -list -v -keystore debug.keystore
命令可以查看到默认的签名信息,以下是在Mac 系统上的查看实例。
- Release模式
Release模式签名过程相对麻烦。具体步骤如下:
1. 生成私人秘钥
可以选择使用JDK 自带的keytool工具生成一个新的秘钥。keytool具体过程不再赘述,有需要的可以自己查阅相关资料。
2. 编译release版本应用程序
这个阶段的编辑过程的具体细节在《Android APK打包流程详解》一文中有分析,在平常开发中,其实是Eclipse或者Android Studio 这些集成开发环境帮我们执行了这些过程,因此我们并不能直观感受到这个具体编译细节。
3. 利用相关工具对应用程序进行签名
JDK提供了Jarsinger来完成签名过程。当然也有其他替代工具,例如signapk等。
4. 最后对签名后的程序进行对齐优化
在《Android APK打包流程详解》一文中提到了打包过程最后会利用zipalign工具对apk进行对齐优化,这种方式保证了所有数据能够按照特定标准来相对文件开头进行字节对齐。
大多数情况下,我们很少采用命令行方式对应用进行签名,IDE已经集成了可视化引导操作,使签名打包流程对开发者更加友好和透明
例如在AS中,可以选择菜单Build->Generate Signed APK ,并遵循指引来完成应用程序的签名。
生成签名的APK菜单选项
填签名信息界面
APK签名的好处
APK的签名机制大致有以下几个好处。
应用程序升级
如果想无缝升级一个应用,Android系统要求应用程序的新版本与老版本具有相同的签名与包名。若包名相同而签名不同,系统会拒绝安装新版应用。
应用程序模块化
Android系统可以允许同一个证书签名的多个应用程序在一个进程里运行,系统实际把他们作为一个单个的应用程序。此时就可以把我们的应用程序以模块的方式进行部署,而用户可以独立的升级其中的一个模块。
代码或数据共享
Android提供了基于签名的权限机制,一个应用程序可以为另一个以相同证书签名的应用程序公开自己的功能与数据,同时其它具有不同签名的应用程序不可访问相应的功能与数据。
应用程序的可认定性
签名信息中包含有开发者信息,在一定程度上可以防止应用被伪造。例如网易云加密对Android APK加壳保护中使用的“校验签名(防二次打包)”功能就是利用了这一点。
Android签名原理
对一个APK文件签名之后,APK文件根目录下会增加META-INF目录,该目录下增加三个文件(来源自网易新闻Android客户端)
MANIFEST.MF
NEWSREAD.RSA
NEWSREAD.SF
其中.RSA文件还可能是.DSA文件,RSA与SF文件的文件名可以更改,但是它们的命名必须一样。
- MANIFEST.MF
保存了APK里所有文件的SHA1校验值的BASE64编码,格式如下(一个文件对应一条记录):
Name: r/w/a6u.png
SHA1-Digest: /pPrsICmOD38EO9yMrV8JViJEo4=
Name: r/w/a87.png
SHA1-Digest: 6ywZNvqc9dj5nbzQK46sKLbMJg0=
Name: r/g/cx.xml
SHA1-Digest: t8hadMWIX60nLdVGQMvurxR66ls=
Name: r/r/d.png
SHA1-Digest: 7/7bMrsNwWq8/StVgGHNL16txDU=
Name: r/v/ma.9.png
SHA1-Digest: BmwsKC3uNvwcF8agRRgehS1CAm0=
Name: r/y/hc.xml
SHA1-Digest: /OBeKIp7Uyej7ifirl1R7ofNdYA=
Name: r/d/zx.xml
SHA1-Digest: ijcN92jK3KqvMe79udBZcCSrNGc=
Name: r/g/gp.xml
SHA1-Digest: keL4Bbx4nra0iVNT2nL0/42JT10=
Name: r/g/i2.xml
SHA1-Digest: MutnxGg3fUc28EPFbWNBHqiwTLI=
- SF文件
SF文件是Signature File文件的缩写,这就是我们所说的签名文件。它是对”某个文件”的Hash值进行私钥加密产生的。理论上,可以对每个文件的摘要分别进行签名,但Android采取了更加巧妙的方式,它只对整个MANIFEST.MF文件进行加密,保存MANIFEST.MF文件的SHA1校验值的BASE64编码,同时还保存了MANIFEST.MF中每一条记录的SHA1检验值BASE64编码,格式如下:
Signature-Version: 1.0
SHA1-Digest-Manifest-Main-Attributes: l+U+0JcdSCrDnnm1YrxW82YjaTE=
**SHA1-Digest-Manifest: coA0RT+4S4898e5ZM2eZDxZICSQ=**
Created-By: 1.8.0_77 (Oracle Corporation)
Name: r/w/a6u.png
SHA1-Digest: 9U6mmpwdsSrkLv9cVaMU52LzhLc=
Name: r/w/a87.png
SHA1-Digest: IMDWmkcj0UPBbpMocKRFbqWSKBY=
Name: r/g/cx.xml
SHA1-Digest: lzBgy/LB6ZCF7wHU68hssXvZi+g=
Name: r/r/d.png
SHA1-Digest: ImPBfTCD6V2BG7uYKZYWlu6QwMQ=
Name: r/v/ma.9.png
SHA1-Digest: UMKiaDOupjwficuJc/fx9i7aEVg=
Name: r/y/hc.xml
SHA1-Digest: z0esvJQWp1TAy1pOSwFwB7oU5S8=
Name: r/d/zx.xml
SHA1-Digest: 061fpsQrt1PnCfYdIyfwyAThzjU=
- RSA文件
这是应用程序开发者提供的证书,对生成的 CERT.SF文件, 用私钥计算出签名, 然后将签名以及包含公钥信息的数字证书一同写入 CERT.RSA 中保存。
RSA文件是加密的,我们可以通过openssl命令
openssl pkcs7 -inform DER -in NEWSREAD.RSA -print_certs -text
可以查看到具体的证书信息,下图是网易新闻APP的证书信息。
下图展示了这三个文件具体的关系。
Android系统就是根据这三个文件的内容对APK文件进行签名检验的。
APK防止篡改的过程
下面着重分析以下这三个文件是如何防止apk文件被篡改的。
首先,如果你改变了apk包中的任何文件,那么在apk安装校验时,改变后的文件摘要信息与MANIFEST.MF的检验信息不同,于是验证失败,程序就不能成功安装。
其次,如果你对更改的过的文件相应的算出新的摘要值,然后更改MANIFEST.MF文件里面对应的属性值,那么必定与CERT.SF文件中算出的摘要值不一样,照样验证失败。
最后,如果你还不死心,继续计算MANIFEST.MF的摘要值,相应的更改CERT.SF里面的值,那么数字签名值必定与CERT.RSA文件中记录的不一样,还是失败。
那么能不能继续伪造数字签名呢?不可能,因为没有数字证书对应的私钥。
所以,如果要重新打包后的应用程序能再Android设备上安装,必须对其进行重签名,否则会提示安装失败。
参考资料
《深入理解Android内核设计思想》
Android签名机制之—签名过程详解