Android 签名那点事儿

cytonn-photography-604680-unsplash_meitu_1

针对 Android 中签名的相关问题,做一些记录整理。

以前,遇到许多关于签名的问题

  1. APK 安装时的校验
  2. 成为 Android 系统级应用
  3. 查看应用的MD5或者是SHA1信息
  4. v2签名
  5. ….

这些问题都将在后面得到答案。

什么是签名

首先,什么是签名?为什么需要签名?

在生活中,一般我们对某个文件进行签名,代表签名者对此文件的认可,防止签名者抵赖,同时防止文件被他人篡改。在计算机中也一样,签名就是对某个文件的一种认证过程,而签名校验就可以有效防止文件被恶意篡改,证明此文件是签名者的原始文件。


数字签名

签名的流程如下:

利用一个单向哈希函数对原始文件进行运算,生成数字摘要,然后用私钥加密这个数字摘要,这个加密后的数字摘要就是数字签名,最后将数字签名和原始文件一起打包成一个新的文件,如此,这个原始文件就被签名了。

校验签名的流程如下:
拿到被签名后的文件之后,首先提取出原始文件与签名,然后使用相同的单向哈希函数对原始文件运算,生成数字摘要,然后用公钥解密数字签名,然后对比两个数字摘要,如果相同就表示校验成功。


数字签名是非对称加密与数字摘要的组合应用,它有两种功效:

  1. 确定文件(消息)确实是由签名者签名并发出来的,因为别人假冒不了签名者的签名。
  2. 数字签名能确定消息的完整性。

当然,数字签名一般不单独使用,基本都是用在数字证书里面。


Android 签名

Android 要求所有已安装的应用程序都使用数字证书做数字签名,数字证书的私钥由开发者持有。

Android 使用数字证书作为标识应用程序开发者的一种方式,并在应用程序之间建立信任的关系,证书并不用来控制用户能否安装那个应用程序。

Android 的数字证书与普通数字证书最大的区别是,Android 数字证书并不需要权威的数字证书签名机构(CA)认证,它只是用来让应用程序包自我认证的,完全可以使用自签名证书(seft-signed certificates)。

没有正确签名的应用,Android系统不会安装或运行,此规则适用于任何地方运行的Android系统,不管是在模拟器还是在真实设备上。即使是开发人员调试时的应用程序,也是使用了默认的签名文件 (目录:用户名/.android/debug.keystore,密码:android)进行签名的。

只有签名文件相同且包名相同的 apk 才可以覆盖安装并保留用户信息,这样做是为了防止已安装的应用被恶意的第三方覆盖或替换。

此外,数字证书都是有有效期的,Android 只是在应用程序安装的时候才会检查证书的有效期。如果程序已经安装在系统中,即使证书过期也不会影响程序的正常功能。


Android 签名的作用

Android 签名的主要作用是为了

  • 应用程序升级:如果你希望用户无缝升级到新的版本,那么你必须用同一个证书进行签名。这是由于只有以同一个证书签名,系统才会允许安装升级的应用程序。如果你采用了不同的证书,那么系统会要求你的应用程序采用不同的包名称,在这种情况下相当于安装了一个全新的应用程序。如果想升级应用程序,签名证书要相同,包名称要相同!
  • 应用程序模块化:Android系统可以允许同一个证书签名的多个应用程序在一个进程里运行,系统实际把他们作为一个单个的应用程序,此时就可以把我们的应用程序以模块的方式进行部署,而用户可以独立的升级其中的一个模块
  • 代码或者数据共享:Android提供了基于签名的权限机制,那么一个应用程序就可以为另一个以相同证书签名的应用程序公开自己的功能。以同一个证书对多个应用程序进行签名,利用基于签名的权限检查,你就可以在应用程序间以安全的方式共享代码和数据了。

所以一旦给Apk签名并上线后,签名文件和密码别名等一定要记住不能丢失,否则会损失用户且带来灾难性的后果.


签名文件格式

签名文件格式有很多种,这里主要是介绍 Android 相关的,比如最早的 keystore、jks、pem/pk8等。

  • KeyStore: KeyStore 是 Eclipse 开发 Android 的时候最早的签名文件了。
  • JKS (Java key store): jks 是目前 Android Studio 中创建签名文件的格式 (Build -> Generate Signed APK) 即可创建和使用签名文件为对应apk进行签名
  • pem/pk8 :这个是系统的签名文件,Android系统在编译的时候也是需要签名,所以这个是系统的签名文件,如果想使自己的应用变成系统应用,则必须使用系统的签名文件进行签名。


Signature Versions V1、V2

在新的 Android studio 版本中,出现了 v2 签名,先看看官方解释:

Signature Versions V1、V2

V1:通过ZIP条目进行验证,这样APK 签署后可进行许多修改,可以移动甚至重新压缩文件。
V2:验证压缩文件的所有字节,而不是单个 ZIP 条目,因此,在签名后无法再更改(包括 zipalign)。正因如此,现在在编译过程中,我们将压缩、调整和签署合并成一步完成。好处显而易见,更安全而且新的签名可缩短在设备上进行验证的时间(不需要费时地解压缩然后验证)。

只勾选v1签名并不会影响什么,但是在7.0上不会使用更安全的验证方式 。
只勾选V2签名7.0以下会直接安装完显示未安装,7.0以上则使用了V2的方式验证
同时勾选V1和V2则所有机型都没问题

或者在app的build.gradle的android标签下加入如下

1
2
3
4
5
6
7
8
9
10
signingConfigs {
debug {
v1SigningEnabled true
v2SigningEnabled true
}
release {
v1SigningEnabled true
v2SigningEnabled true
}
}

建议把V1和V2两个选项全部勾选,如果全部勾选出现了问题,那么可以忽略这种新的签名机制,只勾选第一个选项(V1),依旧使用我们之前老的签名机制。


生成数字证书

生成数字证书有两种方式,包括带图形界面的 AS,以及命令行的keytool。

Android Studio

在 Android studio 中生成签名文件非常简单,build -> Generate Signed APK -> Create new…

生成 keystore

填写完信息之后就生成了数字证书,之后下一步就给 apk 签名上了。

AS 签名带界面的,自然方便,但有时候需要使用命令行工具。

签名相关的两个工具都在 JDK 中

  • keytool 是个密钥和证书管理工具,可以用来生成证书。
  • jarsigner 工具利用密钥仓库中的信息来产生或校验 Java 存档 (JAR) 文件的数字签名


Keytool 生成

使用keytool生成证书:

1
keytool -genkey -keystore test.keystore -alias test -keyalg RSA -validity 10000

参数解释:

  1. -genkey 产生证书文件
  2. -keystore 指定密钥库的.keystore文件中
  3. -alias 指定别名
  4. -keyalg 指定密钥的算法,这里指定为RSA(非对称密钥算法)
  5. -validity 为证书有效天数


jarsigner 签名

数字证书生成后,需要使用 jarsigner 来签名

1
jarsigner -verbose -keystore test.keystore -signedjar -signed.apk unsigned.apk 'test'

参数说明:

  1. -verbose:指定生成详细输出
  2. -keystore:指定数字证书存储路径
  3. -signedjar:该选项的三个参数为 -签名后的apk包,-未签名的apk包,-数字证书别名(注意顺序)


查看签名文件

在使用一些第三方库时(如分享、百度地图),有时会被要求提供 MD5 或者 SHA1值。

查看签名文件信息需要用到 keytool 工具,keytool 是 JDK 自带的工具,需要配置环境变量,输入以下命令:

1
keytool -list -v -keystore <keystore文件名>

例如,查看位于 .android 目录下默认的签名文件 debug.keystore 的信息:

查看签名文件

此命令需要提供 签名文件的密码, debug.keystore 文件的别名是 androiddebugkey ,密码是 android ,之后输出了签名文件的 MD5、SHA1、SHA256的值。


系统签名

普通应用程序的权限受限制,需要系统应用权限才行,因此在定制化系统中,需要将应用程序升级为系统应用程序,这时候就需要系统签名。

这里有两种方案。

使用Android签名工具重新签名

  1. 提供对应平台签名文件「platform.pk8」和「platform.x509.pem」,如果是定制系统,为了省事儿,直接找编译系统的兄弟讨要,如果是google 原生系统,则可以到源码处下载,8.0.0_r4 的两个文件地址在此 ,其他平台版本的位置类似。

  2. 提供签名工具「signapk.jar」,8.0.0_r4的签名工具地址在此,其他平台版本的位置类似。

  3. 将签名证书「platform.pk8」、「platform.x509.pem 」,签名工具「signapk.jar 」放置在同一个文件夹,执行命令

    1
    java -jar signapk.jar platform.x509.pem platform.pk8 Demo.apk signedDemo.apk


生成系统debug.keystore文件

这种方式的好处就是不用每次都手动打包,可以直接配置在 AS 中,同样需要前面的平台签名文件「platform.pk8」和「platform.x509.pem」。

  1. 把pkcs8 格式的私钥转化成 pkcs12 格式:

    1
    openssl pkcs8 -in platform.pk8 -inform DER -outform PEM -out shared.priv.pem -nocrypt
  2. 把 x509.pem 公钥转换成 pkcs12 格式

    1
    openssl pkcs12 -export -in platform.x509.pem -inkey shared.priv.pem -out shared.pk12 -name androiddebugkey

    密码都是:android

  1. 生成debug.keystore

    1
    keytool -importkeystore -deststorepass android -destkeypass android -destkeystore debug.keystore -srckeystore shared.pk12 -srcstoretype PKCS12 -srcstorepass android -alias androiddebugkey


参考

Android安全加密:数字签名和数字证书

使用Java自带的keytool工具生成RSA非对称密钥证书,并导出公钥文件

Android签名机制之—签名过程详解

Android Studio打包签名 Signature Versions V1、V2的选择问题

【Android 进阶】Apk 使用系统签名

给第三方apk进行系统签名的几种方式

Android Studio查看SHA1和MD5(附带keystore创建)


坚持分享技术,但行好事,莫问前程 ~^o^~