apk签名原理

2021-04-09  本文已影响0人  xuefeng_apple

经常使用的总结:

debug 签名:
development/tools/make_key media '/C=CN/ST=BeiJing/L=ChaoYang/O=xxx/OU=debug/CN=xxx/emailAddress=cm@xxx.com'
development/tools/make_key networkstack '/C=CN/ST=BeiJing/L=ChaoYang/O=/OU=xxx/CN=xxx/emailAddress=cm@xxx.com'
development/tools/make_key platform '/C=CN/ST=BeiJing/L=ChaoYang/O=xxx/OU=debug/CN=xxx/emailAddress=cm@xxx.com'
development/tools/make_key shared '/C=CN/ST=BeiJing/L=ChaoYang/O=xxx/OU=debug/CN=xxx/emailAddress=cm@xxx.com'
development/tools/make_key testkey '/C=CN/ST=BeiJing/L=ChaoYang/O=xxx/OU=debug/CN=xxx/emailAddress=cm@xxx.com'

user签名:
development/tools/make_key media '/C=CN/ST=BeiJing/L=ChaoYang/O=xxx/OU=user/CN=xxx/emailAddress=cm@xxx.com'
development/tools/make_key networkstack '/C=CN/ST=BeiJing/L=ChaoYang/O=user/OU=Pwe/CN=xxx/emailAddress=cm@xxx.com'
development/tools/make_key platform '/C=CN/ST=BeiJing/L=ChaoYang/O=xxx/OU=user/CN=xxx/emailAddress=cm@xxx.com'
development/tools/make_key shared '/C=CN/ST=BeiJing/L=ChaoYang/O=xxx/OU=user/CN=xxx/emailAddress=cm@xxx.com'
development/tools/make_key testkey '/C=CN/ST=BeiJing/L=ChaoYang/O=xxx/OU=user/CN=xxx/emailAddress=cm@xxx.com'

ota:
../development/tools/make_key releasekey '/C=CN/ST=BeiJing/L=ChaoYang/O=xxx/OU=xxx/CN=xxx/emailAddress=cm@xxxx.com'

查看生成的格式文件:
keytool -printcert -file platform.x509.pem

使用signapk.jar 进行签名:android10:
java -Djava.library.path="out/host/linux-x86/lib64" -jar out/host/linux-x86/framework/signapk.jar build/target/product/security/platform.x509.pem build/target/product/security/platform.pk8 old.apk  new.apk

android 11:
./soong/host/linux-x86/framework/signapk.jar

如何产生jsk (keystore)文件, 只做了debug 模式发的
./keytool-importkeypair -k test.jks -p android -pk8 platform.pk8 -cert platform.x509.pem -alias test

如何查看test.jks 是否正确:
keytool -list -v -keystore test.jks
 
Android studio 如何使用:
signingConfigs {
    releaseConfig {
        keyAlias 'test'
        keyPassword 'android '
        storeFile file('/home/xxx/tools/keystore/test.jks')
        storePassword 'android '
    }
}



AndroidManifest.xml的manifest节点中添加
android:sharedUserId=”android.uid.system”,
Android.mk中增加  LOCAL_CERTIFICATE := platform 

APK中的META-INF/CERT.RSA
签名之后如何对RSA 进行查看,签名的信息,在android root目录 
openssl pkcs7 -inform DER -in CERT.RSA -noout -print_certs -text

本文主要讲解签名的原因,签名怎么保证数据的正确,主要知识点

1-数据摘要

就是对一个数据源进行一个算法之后得到一个摘要,也叫作数据指纹,不同的数据源,数据指纹肯定不一样,就和人一样

消息摘要算法(Message Digest Algorithm)是一种能产生特殊输出格式的算法,其原理是根据一定的运算规则对原始数据进行某种形式的信息提取,被提取出的信息就被称作原始数据的消息摘要。
著名的摘要算法有RSA公司的MD5算法和SHA-1算法及其大量的变体。

2-签名文件和证书

消息的发送者来说,先要生成一对公私钥对,将公钥给消息的接收者

消息的接受者来说,收到了:原始的消息内容+附加数字签名.
接收者收到内容:原始的消息内容+私钥对[原始数据摘要]

验证正确需要数据摘要算法+公钥,公钥假设是正确的。
如何验证:数据摘要算法对内容提取摘要 对比公钥解密签名

图示验证过程:

3-如何保证公钥是正确的

数字证书,一般包含以下一些内容:

APP 是如何保证签名流程的:
apk签名其实是对所有源文件单独计算摘要, 然后用私钥加密摘要信息再得到一个加密串, 我们称之为
APK的签名. 你对源文件的修改都会导致签名的变化. 这个是为了验证apk没有被篡改.

app的升级和重新安装, 检测的并不是这个apk签名, 而是你的包名+私钥的摘要信息, 签名的keystore文件没有变, 私钥的摘要信息也就不会变了.

google APP store, 当开发者第一步开发的时候,就需要有自己的签名,私钥的摘要信息上传到goole APP store, 如果升级的时候, 私钥的摘要不一致肯定不能升级app 的上传,这里应该做了校验的。

4-签名Apk包与没有签名的APK 差异在哪里

源码位置:com/android/signapk/sign.java
Android签名apk之后,会有一个META-INF文件夹,这里有三个文件:

MANIFEST.MF是:
逐一遍历里面的所有条目,如果是目录就跳过,如果是一个文件,就用SHA1(或者SHA256)消息摘要算法提取出该文件的摘要然后进行BASE64编码后,作为“SHA1-Digest”属性的值写入到MANIFEST.MF文件中的一个块中。该块有一个“Name”属性,其值就是该文件在apk包中的路径。

CERT.SF:
逐条计算MANIFEST.MF文件中每一个块的SHA1,并经过BASE64编码后,记录在CERT.SF中的同名块中,属性的名字是“SHA1-Digest

CERT.RSA:
把之前生成的 CERT.SF文件, 用私钥计算出签名, 然后将签名以及包含公钥信息的数字证书一同写入 CERT.RSA 中保存,还有私钥的摘要信息

5-如何对apk 进行签名

5.1生成签名文件

development/tools/make_key testkey  '/C=US/ST=California/L=Mountain View/O=Android/OU=Android/CN=Android/emailAddress=android@android.com'

development/tools/make_key platform '/C=US/ST=California/L=Mountain View/O=Android/OU=Android/CN=Android/emailAddress=android@android.com'

如何查看生成的platform.X509.pem:
build/target/product/security/platform.x509.pem
keytool -printcert -file platform.x509.pem
或者
openssl x509 -inform PEM -subject_hash_old -in platform.x509.pem -text

单独给APP签名方法:
java -Djava.library.path="out/host/linux-x86/lib64" -jar out/host/linux-x86/framework/signapk.jar build/target/product/security/platform.x509.pem build/target/product/security/platform.pk8 old.apk new.apk

APP签名之后,如何查看CERT.RSA 信息
openssl pkcs7 -inform DER -in CERT.RSA -noout -print_certs -text

6-Android OTA releasekey 替换

6.1生成key
系统默认的key如下,首先需要产生以下4种我们项目自己的OTA签名key文件,每一种类型的key都是成对生成的,.509.pem后缀名的是公钥,.pk8后缀名的是私钥。
testkey -- a generic key for packages that do not otherwise specify a key.
platform -- a test key for packages that are part of the core platform.
shared -- a test key for things that are shared in the home/contacts process.
media -- a test key for packages that are part of the media/download system.

将XXX替换为自己公司信息。
生成文件如下:
media.pk8 media.x509.pem platform.pk8 platform.x509.pem
releasekey.pk8 releasekey.x509.pem shared.pk8 shared.x509.pem

将生成的key 文件放到项目相关的目录下,针对Amlogic项目放到device/amlogic/p341/sign_keys。这样我们公司的key就生成了。

6.2.更改编译规则,使编译过程中使用我们新生成的key对OTA进行签名
首先在build/core/Makefile里搜索testkey, 查看testkey是怎么用到编译系统的,看到如下编译选项:

 ifeq ($(DEFAULT_SYSTEM_DEV_CERTIFICATE),build/target/product/security/testkey)
 BUILD_KEYS := test-keys
 else
 BUILD_KEYS := dev-keys
 endif

继续查看DEFAULT_SYSTEM_DEV_CERTIFICATE,可以看到在build/core/config.mk文件里有如下:

 # The default key if not set as LOCAL_CERTIFICATE
 ifdef PRODUCT_DEFAULT_DEV_CERTIFICATE
   DEFAULT_SYSTEM_DEV_CERTIFICATE := $(PRODUCT_DEFAULT_DEV_CERTIFICATE)
 else
   DEFAULT_SYSTEM_DEV_CERTIFICATE := build/target/product/security/testkey
 endif

因此要想使用releasekey,只需要指定PRODUCT_DEFAULT_DEV_CERTIFICATE的值即可,因此在device/amlogic/p341/p341.mk中指定项目特定变量
PRODUCT_DEFAULT_DEV_CERTIFICATE := device/amlogic/p341/sign_keys/releasekey
同时在根据规则,在build/core/Makefile改动如下:

 ifeq ($(DEFAULT_SYSTEM_DEV_CERTIFICATE),device/amlogic/p341/sign_keys/releasekey)
 BUILD_KEYS := release-keys
 endif

6.3. Androoid.mk 使用platform 签名
对于apk的签名,系统会根据apk里指定的key进行签名。如果系统中的apk的android.mk中没有设置LOCAL_CERTIFICATE的值,就默认使用testkey。

 ifeq ($(LOCAL_CERTIFICATE),)
     LOCAL_CERTIFICATE := $(DEFAULT_SYSTEM_DEV_CERTIFICATE)
 endif
 private_key := $(LOCAL_CERTIFICATE).pk8
 certificate := $(LOCAL_CERTIFICATE).x509.pem

而如果设置成:
LOCAL_CERTIFICATE := platform
就代表使用platform来签名,这样的话这个apk就拥有了和system相同的签名
如何产生jks文件,提供给android studio 开发使用,进行系统签名
jks文件:
第一种方式
https://github.com/chear/keytool-importkeypair
./keytool-importkeypair -k test.jks -p android -pk8 platform.pk8 -cert platform.x509.pem -alias test
最终会生成 test.jks
-k test.jks: test表示最终生成的jks的名字,可以自定义
android : 输入当前jks的密码,可以自定义。
alias test: test表示别名,可以自定义,建议和上面的jks一致。

第二种方式: 该方式作为记录,实际与第一种方式是想通的,可以看keytool-importkeypair 脚本

1、编译android源码。
2、cd build/target/product/security/ 
3、执行
openssl pkcs8 -inform DER -nocrypt -in platform.pk8 -out platform.pem
生成platform.pem文件

4、
openssl pkcs12 -export -in platform.x509.pem -out platform.p12 -inkey platform.pem -password pass:123456 -name test
生成platform.p12文件,其中 "test" 为alias名(app添加签名要用到),"123456" 为密码。

5、执行 
keytool -importkeystore -deststorepass test -destkeystore platform.jks -srckeystore platform.p12 -srcstoretype PKCS12 -srcstorepass test
 
生成platform.jks (app打签名最终用到的文件),
-deststorepass "123456" 设置的是这个签名的密码,
-src*     的其他参数都是从前面两个指令中生成的。
 
6、生成platform.jks
keytool -importkeystore -srckeystore platform.jks -destkeystore platform.jks -deststoretype pkcs12

说明:platform.jks 实际是含有了公钥与私钥, 这个是不能release给第三方的,只能给自己公司研发使用

思考:

7 设计原则与测试结果

7.1设计原则
签名文件规格:(device.mk设计参考之前的)
1)Userdebug 与user 区别
userdebug 系统platform.jks 有可能release 给别人,因此user版本设计成不一样的。
user 系统platform.jks 仅仅relase公司的app 开发人员
2)user 与ota ,只是ota 多了releaseky,其他文件都一样

7.2测试华为手机user version【开发者模式】:

Performing Streamed Install
adb: failed to install C:\Users\Desktop\old.apk: Failure [INSTALL_FAILED_UPDATE_INCOMPATIBLE: Package com.example.demo signatures do not match previously installed version; ignoring!]

REF:
https://www.jianshu.com/p/76e5f5e64b85
https://developer.android.google.cn/studio/publish/app-signing
ota relase key 参考

下载文件地址:
git clone https://github.com/getfatday/keytool-importkeypair.git

上一篇下一篇

猜你喜欢

热点阅读