常见的密钥库(keystore
)文件格式如下:
格式 : 扩展名
格式 : JKS
扩展名 : .jks/.ks
描述 : [Java Keystore]密钥库的Java实现版本,provider为SUN
特点 : 密钥库和私钥用不同的密码进行保护
格式 : JCEKS
扩展名 : .jce
描述 : [JCE Keystore]密钥库的JCE实现版本,provider为SUN JCE
特点 : 相对于JKS安全级别更高,保护Keystore私钥时采用TripleDES
格式 : PKCS12
扩展名 : .p12/.pfx
描述 : [PKCS #12]个人信息交换语法标准
特点 : 1、包含私钥、公钥及其证书
2、密钥库和私钥用相同密码进行保护
格式 : BKS
扩展名 : .bks
描述 : Bouncycastle Keystore]密钥库的BC实现版本,provider为BC
特点 : 基于JCE实现
格式 : UBER
扩展名 : .ubr
描述 : [Bouncycastle UBER Keystore]密钥库的BC更安全实现版本,provider为BC
还有一个*.keystore
是Eclipse
打包生成的签名
点击查看android studio生成上传密钥和密钥库官方介绍
这里生成的是jks
后缀的文件,直接使用apksigner.jar
签名一点问题都没有,但是,如果在android手机端运行加载,就会报错:java.io.IOException: Wrong version of key store.
这是因为:Java平台默认识别jks格式的证书文件,但是android平台只识别bks格式的证书文件。
解决方案:安装keystore-explorer
(后面会有介绍),将原始的JKS
证书改成BKS
。
keystore-explorer
打开原来的BKS证书,选择Tools->Change Type
, 选择BKS
,然后把文件另存为*.bks
即可使用。
特别注意,在android手机端使用
bks
签名的包必须是release
版本的apk,不然可能被提示安装未完成。
以下是搜集的一些简介:
jarsigner
+apksigner
简介jarsigner是JDK提供的针对jar包签名的通用工具,
位于JDK/bin/jarsigner.exe
apksigner是Google官方提供的针对Android apk签名及验证的专用工具,
位于Android SDK/build-tools/SDK版本/apksigner.bat
不管是apk包,还是jar包,本质都是zip格式的压缩包,所以它们的签名过程都差不多(仅限V1签名),
以上两个工具都可以对Android apk包进行签名.
在Android Studio中点击菜单 Build->Generate signed apk... 打包签名过程中,
可以看到两种签名选项 V1(Jar Signature) V2(Full APK Signature),
刚开始升级AS看到这个懵了,既然是APK Signature,就放心偷懒选了V2,结果安装失败???无奈,只能查资料...
从Android 7.0开始, 谷歌增加新签名方案 V2 Scheme (APK Signature);
但Android 7.0以下版本, 只能用旧签名方案 V1 scheme (JAR signing)
V1签名:
来自JDK(jarsigner), 对zip压缩包的每个文件进行验证, 签名后还能对压缩包修改(移动/重新压缩文件)
对V1签名的apk/jar解压,在META-INF存放签名文件(MANIFEST.MF, CERT.SF, CERT.RSA),
其中MANIFEST.MF文件保存所有文件的SHA1指纹(除了META-INF文件), 由此可知: V1签名是对压缩包中单个文件签名验证
V2签名:
来自Google(apksigner), 对zip压缩包的整个文件验证, 签名后不能修改压缩包(包括zipalign),
对V2签名的apk解压,没有发现签名文件,重新压缩后V2签名就失效, 由此可知: V2签名是对整个APK签名验证
V2签名优点很明显:
签名更安全(不能修改压缩包)
签名验证时间更短(不需要解压验证),因而安装速度加快
注意: apksigner工具默认同时使用V1和V2签名,以兼容Android 7.0以下版本
位于Android SDK/build-tools/SDK版本/zipalign.exe
zipalign 是对zip包对齐的工具,使APK包内未压缩的数据有序排列对齐,从而减少APP运行时内存消耗
zipalign -v 4 in.apk out.apk //4字节对齐优化
zipalign -c -v 4 in.apk //检查APK是否对齐
zipalign可以在V1签名后执行
但zipalign不能在V2签名后执行,只能在V2签名之前执行!!!
Android Studio
在Debug
时,对App
签名都会使用一个默认的密钥库:
默认在C:\Users\用户名\.android\debug.keystore
密钥库名: debug.keystore
密钥别名: androiddebugkey
密钥库密码: android
比如我这边使用的自定义密钥:
signingConfigs {
hgy413 {
storeFile file('C:\\H\\Android\\key\\hgy413.jks')
storePassword '654321'
keyPassword '654321'
keyAlias = 'hgy413'
}
}
cmd
,把目录切换到SDK
的build-tools
目录下(例如: C:\Users\Administrator\AppData\Local\Android\Sdk\build-tools\26.0.2
)zipalign.exe
。把我们要签名的apk
拷到同目录。
zipalign.exe
命令选项:
-f
: 输出文件覆盖源文件
-v
: 详细的输出log
-p
: outfile.zip should use the same page alignment for all shared object files within infile.zip
-c
: 检查当前APK是否已经执行过Align优化。
执行以下两条命令:
zipalign.exe -c -v 4 app-release.apk
zipalign.exe -v -p 4 app-release.apk appalign.apk
这时会生成一个Align优化后的appalign.apk
。
appalign.apk
签名,打开cmd
,把目录切到SDK\build-tools\版本号\lib
下(例如:C:\Users\Administrator\AppData\Local\Android\Sdk\build-tools\26.0.2\lib
), 把我们要签名的appalign.apk
拷到同目录, 执行:java -jar apksigner.jar sign //执行签名操作
--ks 你的jks路径 //jks签名证书路径
--ks-key-alias 你的alias //生成jks时指定的alias
--ks-pass pass:你的密码 //KeyStore密码
--key-pass pass:你的密码 //签署者的密码,即生成jks时指定alias对应的密码
--out output.apk //输出路径
input.apk //被签名的apk
执行以下两条命令:
java -jar apksigner.jar sign --ks C:\H\Android\key\hgy413.jks --ks-key-alias hgy413 --ks-pass pass:654321 --key-pass pass:654321 --out appsign.apk appalign.apk
java -jar apksigner.jar verify -v appsign.apk
有时在签名前需要把
META-INF
目录下的三个文件先删除掉,不然如果原来MANIFEST.MF
中是sha256
,后面使用了sha1
,就可能导致MANIFEST.MF
中即有sha256
的签名串也有sha1
的签名串,从而可能会被视为未签名,
zipsigner
就可能出现此问题。
直接使用 android studio生成上传密钥和密钥库, 在android中加载时,会抛出异常: load BKS error:wrong version of key store
。
keystore-explorer下载地址,将keystore-explorer安装包下载后,双击安装完成。
然后第一次以管理员权限
打开,默认会弹出提示框:
–>点击Download Unlimited Strength ...
下载更新包。
再点击Browse to Unlimited ..
选择刚下载的更新包,选中后,此时Upgrade
按钮会变为可点,点击完成升级。
不以
管理员权限
打开,升级会失败,因为要把升级包解压并拷贝到C盘安装目录下(C:\Program Files (x86)\KeyStore Explorer\lib
)。
signapk.jar
testkey.x509.pem
testkey.pk8
上述文件可以从 AOSP
系统源码中提取。
把需要签名的app-release.apk
和上述文件放在同目录,运行bat:
java -jar signapk.jar testkey.x509.pem testkey.pk8 app-release.apk app-sign.apk
即可生成带签名的app-sign.apk
。
证书和私钥官方文档
每个密钥都包含两个文件:一个是扩展名为 .x509.pem
的证书,另一个是扩展名为 .pk8
(PCKS8) 的私钥。私钥需要加以保密,并用于对 apk 包进行签名。密钥本身也可能受密码保护。相比之下,证书只包含公开的一半密钥,因此可以大范围地分发。证书被用于验证某个 apk 包是否由相应的私钥进行签名。
Android签名中证书的格式采用X.509
标准的版本三,不过省略了一些内容。可以通过keystore-explorer
右键导出
还可以把CERT.RSA
改成CERT.p7b
, 双击即可看到证书和公钥:
X.509
证书格式如下图所示:
数字证书的格式普遍采用的是X.509V3
国际标准,一个标准的X.509
数字证书包含以下一些内容:
重要说明:编写Java程序和编写Android应用App解析Apk的CERT.RSA文件,得到的结果是不一样的。按道理,都是解析的同一个文件,为什么结果不一样呢?经过我们分析,发现不一样的地方是开发者公钥,但是这是由于二者的显示格式不同导致的。App解析得到的文件时十六进制显示的,而Java解析得到的结果却是十进制显示的。
内容2这一块就是signature block template
, 对于同样的签名规则,即使改变了zip中的其他文件,这一块也不会变化,所以要找它也比较容易,改变文件,多次签名,比较CERT.RSA
,前面相同的部分就是了,或者最后内容二的大小一般为0x100个字节,所以去掉0x100个字节,再转成base64
即可,010可以轻松做到。
利用keystore-explorer
右键Export->Export Key Pair
,选择pem
格式,导出pem
文件,然后打开pem
文件,
其中-----BEGIN PRIVATE KEY-----
到-----END PRIVATE KEY-----
之间的文本对应privateKey
字符串(不含-----BEGIN PRIVATE KEY-----
和-----END PRIVATE KEY-----
),可用于生成PrivateKey
对象, 和android中直接加载keystore
文件得到的PrivateKey
对象完全一样, 参考FFRepack
。
也可把这段内容保存成Privatekey.Key
文件, 运行openssl rsa -in Privatekey.Key -check
,可以得到另一个字符串,同样可以生成PrivateKey
对象,和android中直接加载keystore
文件得到的PrivateKey
对象看起来好像不同,但调用PrivateKey.getEncoded()
比对得到的byte[]完全相同,前面两种字符串均可使用。
而publicKey
(也就是cert
)就是 -----BEGIN CERTIFICATE-----
到-----END CERTIFICATE-----
的字符串(去掉-----BEGIN CERTIFICATE-----
和-----END CERTIFICATE-----
)。将它拷贝成字符串(不含-----BEGIN PRIVATE KEY-----
和-----END PRIVATE KEY-----
),即可用于代码, 参考FFRepack
。
通过命令行cmd进入jdk的bin目录下,会发现有一个keytool.exe文件,如: C:\Program Files\Java\jdk1.8.0_73\bin
keytool -genkey -alias hgy.keystore -keyalg RSA -validity 36500 -keystore winter.keystore
-genkey 生成文件。
-alias 别名。
-keyalg 加密算法。
-validity 有效期。
-keystore 文件名。
36500 表示100年
参考: Android签名与认证详细分析之二(CERT.RSA剖析)