签名
通过签名可以确保数据来源的可靠性和数据的不可篡改性
对 Apk 进行签名,也就是在 Apk 中写入一个指纹,写入指纹后,Apk 中有任何修改,都会导致这个指纹无效,Android 系统在安装 Apk 进行签名校验时就会不通过,进而无法安装该 Apk
签名和校验过程
webp.jpg
如上图:
签名过程
- 通过 Hash 算法提取出原始数据的摘要 x
- 使用私钥对摘要进行非对称加密算法,得到签名信息
- 将签名信息写入原始数据的签名区块内
校验过程
- 用同样的 Hash 算法从接收到的数据中提取出摘要 x
- 使用发送方的公钥对数字签名进行解密,解密出原始摘要 y
- 判断 x 是否等于 y,等于则校验通过,否则不通过
通常的签名验签过程中,接收方收到消息后,会先向 CA 机构验证证书的合法性,再进行签名校验。但 Apk 的证书通常由开发者自己制作,没有向 CA 机构申请,Android 系统在安装 Apk 时也并没有校验证书本身的合法性,只是从证书中提取公钥和加密算法,因此,如果对第三方 Apk 重新签名,也能安装到没有安装过这个 Apk 的系统中
keystore 文件
keystore 文件包含私钥、公钥和数字证书,分为很多种,Android 使用的是 Java 标准 keystore 格式 JKS(Java Key Storage)
生成签名文件(jks文件)方法
在 Build菜单中选择 Generate Signed Bundle / APK...
image-20211203135846625.png
选择 APK
Android App Bundle:用于通过 Google Play 发布的应用,需要升级到AS 3.2 以上版本才支持App Bundle 格式;
APK:用于创建可部署到设备上的签名 APK
image-20211203140000120.png
点击 Create new... 创建密钥库
image-20211203140212438.png
点击 Key store path 选择密钥库文件路径,填写密钥库名称,点击 OK 确定
image-20211203140614776.png
填入信息后点击 OK
image-20211203141228180.png
点击OK
image-20211203141255354.png
image-20211203142235585.png
点击 Finish 就会生成签名文件与签名后的 Apk
自动签名
当我们需要升级 Apk 版本的时候,需要再次对 Apk 文件进行签名,可以通过配置 build.gradle 让其自动生成签名后的 Apk
打开 Project Structure
image-20211203143205739.png
填写信息
image-20211203143754051.png
点击OK完成后,会在 app/build.gradle文件中加入以下内容
signingConfigs {
debug {
storeFile file('E:\\software\\AndroidStudio\\key\\keys.jks')
keyAlias 'key0'
storePassword '***'
keyPassword '***'
}
}
自动签名安全性
如果你的项目是开源的,需要把你的签名信息写在 local.properties 中,然后在 .gitignore 配置文件中加入 local.properties ,这样 local.properties 就不会提交到开源项目中,签名信息也就不会被人获取
local.properties:
keyStorePath=E\:\\software\\AndroidStudio\\key\\keys.jks
keyAlias=key0
keyStorePwd=***
keyAliasPwd=***
app/build.gradle:
Properties properties = new Properties()
properties.load(project.rootProject.file('local.properties').newDataInputStream())
def storePath = properties.getProperty('keyStorePath')
def alias = properties.getProperty('keyAlias')
def storePwd = properties.getProperty('keyStorePwd')
def aliasPwd = properties.getProperty('keyAliasPwd')
/*这个闭包中我们可以配置项目构建的各种属性*/
android {
signingConfigs {
debug {
storeFile file(storePath)
keyAlias alias
storePassword storePwd
keyPassword aliasPwd
}
}
......
}
系统签名
有时候我们的 apk 中某些功能需要系统签名,例如静默安装。测试系统签名的 apk,需要 root 权限,而带 Google APIs 的模拟器不能 root,因此要注意不能选择带 Google APIs 的模拟器
image-20211204175627776.png
手动进行系统签名
下面执行的操作都是在 Linux 中,如果 apk 是 window 中生成的,需要拷贝到 linux 操作,再将生成的系统签名过得 apk 再拷贝到 window,比较麻烦,可以考虑后面的自动系统签名,还是需要在 linux 操作一次,不过之后就可以只在 window 操作了
在 aosp 源码中获取 platform.pk8 和 platform.x509.pem 文件
这两个文件在目录 aosp/build/target/product/security 下,如下图
image-20211204151557201.png
获取 signapk.jar 文件
在目录 aosp/prebuilts/sdk/tools/lib 下,如下图
image-20211204154238794.png
执行签名命令
将前面获取的 platform.pk8 、 platform.x509.pem 和 signapk.jar 文件放到需要签名的 apk 同一个目录,执行以下命令
java -jar signapk.jar platform.x509.pem platform.pk8 .\app-debug.apk app-debug_signed.apk
image-20211204164156740.png
如果出现上面的错误:Failed to load any of the given libraries: [conscrypt_openjdk_jni-linux-x86_64, conscrypt_openjdk_jni-linux-x86_64-fedora, conscrypt_openjdk_jni]
解决方法:
到目录 aosp/prebuilts/sdk/tools/linux/lib64 下,复制 libconscrypt_openjdk_jni.so 文件到需要签名 apk 的同一个目录,并将命令改为
java -Djava.library.path=. -jar signapk.jar platform.x509.pem platform.pk8 app-debug.apk app-debug_signed.apk
image-20211204164049076.png
自动进行系统签名
自动进行系统签名的原理是:先生成一个 system.jks 文件,使用 keytool-importkeypair 对 system.jks 文件进行系统签名,再 build.gradle 和 local.properties 进行配置,直接使用带有系统签名的 system.jks 对 apk 进行签名,这样编译生成的apk文件就自带系统签名了
先生成一个 system.jks 文件
按照前面的方法,生成一个 system.jks 文件,此时是在 window 系统中操作的
image-20211204181502288.png
使用 keytool-importkeypair 工具对 jks 文件引入系统签名
下载 keytool-importkeypair 工具
git clone https://github.com/getfatday/keytool-importkeypair.git
image-20211204183118587.png
将 system.jks、platform.pk8、platform.x509.pem 文件放到和 keytool-importkeypair 同一个目录
进入 keytool-importkeypair 目录,将 system.jks、platform.pk8、platform.x509.pem 文件拷贝进来,拷贝之后的目录结构为
image-20211204183500687.png
使用 keytool-importkeypair 对 system.jks 文件进行系统签名
./keytool-importkeypair -k system.jks -p 123456 -pk8 platform.pk8 -cert platform.x509.pem -alias key0
image-20211204183555171.png
使用已经带有系统签名的 system.jks 文件对 apk 进行签名
使用 linux 中修改过的带有系统签名的 system.jks 文件将 window 中最开始生成的 system.jks 覆盖掉,再像前面的自动签名部分一样,修改 build.gradle 和 local.properties 的配置,之后生成的 apk 就是系统签名过的了
测试方法是,在 AndroidManifest.xml 中添加 android:sharedUserId="android.uid.system" 后安装到非 Google APIs 的模拟器上, Google APIs 的模拟器不能 root,无法安装
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.androidstudy"
android:sharedUserId="android.uid.system">
......
会发现只有使用 system.jks 文件签名后才能安装,否则安装失败,会报以下的错误:
Installation did not succeed.
The application could not be installed: INSTALL_FAILED_SHARED_USER_INCOMPATIBLE













网友评论