android-apk签名

##APK Signe
签名是为了什么

为了保证每个应用程序开发商合法ID,防止部分开放商可能通过使用相同的Package Name来混淆替换已经安装的程序,我们需要对我们发布的APK文件进行唯一签名,保证我们每次发布的版本的一致性(如自动更新不会因为版本不一致而无法安装)。

###签名需要了解的知识点

  1. 数据摘要(数据指纹)、签名文件,证书文件
  2. jarsign工具签名和signapk工具签名
  3. keystore文件和pk8文件,x509.pem文件的关系
  4. 如何手动的签名apk

签名文件和证书
发送者:
1)对要发送的原始消息提取消息摘要;
2)对提取的信息摘要用自己的私钥加密。附加上自己的数字证书
接收者:
先使用CA公钥解开数字证书,获取发送者的公钥信息
1)对原始消息部分提取消息摘要,注意这里使用的消息摘要算法要和发送方使用的一致;
2)对附加上的那段数字签名,使用得到的公钥解密;
3)比较前两步所得到的两段消息是否一致。如果一致,则表明消息确实是期望的发送者发的,且内容没有被篡改过;相反,如果不一致,则表明传送的过程中一定出了问题,消息不可信。

数字证书用来保证公钥的可信性。
“证书中心”(certificate authority,简称CA),为公钥做认证。证书中心用自己的私钥,对请求者的公钥和一些相关信息一起加密,生成”数字证书”(Digital Certificate)。
 
数字签名和签名验证的大体流程:

ef7a55cf.png    将apk解压; 找到META-INF 下的.RSA文件; 进入cmd环境,进入.RSA文件文件所在路径,命令: `keytool -printcert -file XXX.RSA` 即可查看签名信息。 ### jarsign工具签名和signapk工具签名 jarsign工具签名时使用的是keystore文件 signapk工具签名时使用的是pk8,x509.pem文件  
jarsigner -verbose -sigalg SHA1withDSA -digestalg SHA1  -keystore D:\jiangwei.keystore -storepass jiangwei D:\123.apk jiangwei

Android 签名方法

apksign.jar由Android SDK提供

java -jar signapk.jar testkey.x509.pem testkey.pk8 update.apk update_signed.apk

它接受一个PEM公钥文件,PK8私钥文件,对update.apk进行签名,签名后的文件保存到update_signed.apk。

openssl pkcs8 -topk8 -outform DER -in userkey.pem  -inform PEM -out userkey.pk8 -nocrypt

.cer/.crt是用于存放证书,它是2进制形式存放的,不含私钥。

jarsinger是由JDK提供,使用方法如下:

jarsigner -verbose -keystore d:\\debug.keystore -signedjar update_signed.apk update.apk androiddebugkey -digestalg SHA1 -sigalg MD5withRSA -keypass android -storepass android

其中:
-keystore表示keystore文件的路径
androiddebugkey 表示keystore中的一个别名
-digestalg表示摘要算法
-sigalg 表示签名算法
-keypass 表示别名密码
-storepass表示keystore密码

对一个APK文件签名之后,APK文件根目录下会增加META-INF目录,该目录下增加三个文件:  

MANIFEST.MF
NETEASE.RSA
NETEASE.SF

其中.RSA文件还可能是.DSA文件,RSA与SF文件的文件名可以更改,但是它们的命名必须一样。
MANIFEST.MF中保存了APK里所有文件的SHA1校验值的BASE64编码,格式如下(一个文件对应一条记录):

Name: res/anim/abc_fade_in.xml
SHA1-Digest: ohPEA4mboaFUu9LZMUwk7FmjbPI=
Name: res/anim/abc_fade_out.xml
SHA1-Digest: MTJWZc22b5LNeBboqBhxcQh5xHQ=

SF文件里保存了MANIFEST.MF文件的SHA1校验值的BASE64编码,同时还保存了MANIFEST.MF中每一条记录的SHA1检验值BASE64编码,格式如下:

SHA1-Digest-Manifest: ZRhh1HuaoEKMn6o21W1as0sMlaU=
Name: res/anim/abc_fade_in.xml
SHA1-Digest: wE1QEZhFkLBWMw4TRtxPdsiMRtA=
Name: res/anim/abc_fade_out.xml
SHA1-Digest: MfCV1efdxSKtesRMF81I08Zyvvo=

CERT.RSA文件
这里我们看到的都是二进制文件,因为RSA文件加密了,所以我们需要用openssl命令才能查看其内容

openssl pkcs7 -inform DER -in CERT.RSA -noout -print_certs -text
753c946c.png

CERT.RSA是一个满足PKCS7格式的文件。这里会把之前生成的 CERT.SF文件, 用私钥计算出签名, 然后将签名以及包含公钥信息的数字证书一同写入 CERT.RSA 中保存。

a1e1448a.png

###名词解释
####CSR

  • Certificate Signing Request,即证书签名请求,这个并不是证书,而是向权威证书颁发机构获得签名证书的申请,其核心内容是一个公钥(当然还附带了一些别的信息),在生成这个申请的时候,同时也会生成一个私钥,私钥要自己保管好.做过iOS APP的朋友都应该知道是怎么向苹果申请开发者证书的吧.
    查看的办法:
openssl req -noout -text -in my.csr

(如果是DER格式的话照旧加上-inform der,这里不写了)

####PEM文件(.pem)
PEM是Privacy Enhanced Mail的缩写
PEM说明该文件是标准X.509证书文件,编码格式为PEM编码。

解密私钥

openssl rsa -in userkey.pem   -out userPri.pem

####X.509
X.509 不是证书文件,是一种证书标准。定义证书文件中结构和内容
###证书编码的转换

  • PEM转为DER
openssl x509 -in cert.crt -outform der -out cert.der

DER转为PEM

openssl x509 -in cert.crt -inform der -outform pem -out cert.pem

(提示:要转换KEY文件也类似,只不过把x509换成rsa,要转CSR的话,把x509换成req…)

PEM,PK8转为key store
使用下面的工具
https://github.com/getfatday/keytool-importkeypair

./keytool-importkeypair -k debug.keystore -p android -pk8 ./userkey.pk8 -cert ./SuoErSi_USER.crt -alias userkey

列出keystore存在的所有证书
keytool -list -v -keystore keystore.jks

JDK中keytool常用参数说明(不同版本有差异,详细可参见【附录】中的官方文档链接):

-genkey 在用户主目录
-genkey 在用户主目录中创建一个默认文件”.keystore”,还会产生一个mykey的别名,mykey中包含用户的公钥、私钥和证书(在没有指定生成位置的情况下,keystore会存在用户系统默认目录)
-alias 产生别名 每个keystore都关联这一个独一无二的alias,这个alias通常不区分大小写
-keystore 指定密钥库的名称(产生的各类信息将不在.keystore文件中)
-keyalg 指定密钥的算法 (如 RSA DSA,默认值为:DSA)
-validity 指定创建的证书有效期多少天(默认 90)
-keysize 指定密钥长度 (默认 1024)
-storepass 指定密钥库的密码(获取keystore信息所需的密码)
-keypass 指定别名条目的密码(私钥的密码)
-dname 指定证书发行者信息 其中: “CN=名字与姓氏,OU=组织单位名称,O=组织名称,L=城市或区域名 称,ST=州或省份名称,C=单位的两字母国家代码”
-list 显示密钥库中的证书信息 keytool -list -v -keystore 指定keystore -storepass 密码
-v 显示密钥库中的证书详细信息
-export 将别名指定的证书导出到文件 keytool -export -alias 需要导出的别名 -keystore 指定keystore -file 指定导出的证书位置及证书名称 -storepass 密码
-file 参数指定导出到文件的文件名
-delete 删除密钥库中某条目 keytool -delete -alias 指定需删除的别 -keystore 指定keystore – storepass 密码
-printcert 查看导出的证书信息 keytool -printcert -file g:\sso\michael.crt
-keypasswd 修改密钥库中指定条目口令 keytool -keypasswd -alias 需修改的别名 -keypass 旧密码 -new 新密码 -storepass keystore密码 -keystore sage
-storepasswd 修改keystore口令 keytool -storepasswd -keystore g:\sso\michael.keystore(需修改口令的keystore) -storepass pwdold(原始密码) -new pwdnew(新密码)
-import 将已签名数字证书导入密钥库 keytool -import -alias 指定导入条目的别名 -keystore 指定keystore -file 需导入的证书
中创建一个默认文件”.keystore”,还会产生一个mykey的别名,mykey中包含用户的公钥、私钥和证书(在没有指定生成位置的情况下,keystore会存在用户系统默认目录)
-alias 产生别名 每个keystore都关联这一个独一无二的alias,这个alias通常不区分大小写
-keystore 指定密钥库的名称(产生的各类信息将不在.keystore文件中)
-keyalg 指定密钥的算法 (如 RSA DSA,默认值为:DSA)
-validity 指定创建的证书有效期多少天(默认 90)
-keysize 指定密钥长度 (默认 1024)
-storepass 指定密钥库的密码(获取keystore信息所需的密码)
-keypass 指定别名条目的密码(私钥的密码)
-dname 指定证书发行者信息 其中: “CN=名字与姓氏,OU=组织单位名称,O=组织名称,L=城市或区域名 称,ST=州或省份名称,C=单位的两字母国家代码”
-list 显示密钥库中的证书信息 keytool -list -v -keystore 指定keystore -storepass 密码
-v 显示密钥库中的证书详细信息
-export 将别名指定的证书导出到文件 keytool -export -alias 需要导出的别名 -keystore 指定keystore -file 指定导出的证书位置及证书名称 -storepass 密码
-file 参数指定导出到文件的文件名
-delete 删除密钥库中某条目 keytool -delete -alias 指定需删除的别 -keystore 指定keystore – storepass 密码
-printcert 查看导出的证书信息 keytool -printcert -file g:\sso\michael.crt
-keypasswd 修改密钥库中指定条目口令 keytool -keypasswd -alias 需修改的别名 -keypass 旧密码 -new 新密码 -storepass keystore密码 -keystore sage
-storepasswd 修改keystore口令 keytool -storepasswd -keystore g:\sso\michael.keystore(需修改口令的keystore) -storepass pwdold(原始密码) -new pwdnew(新密码)
-import 将已签名数字证书导入密钥库 keytool -import -alias 指定导入条目的别名 -keystore 指定keystore -file 需导入的证书