Android Protect-0.签名相关

文章目录

    • 1.签名文件格式
    • 2. 生成上传密钥和密钥库
    • 3. apksigner签名
      • 3.1. 签名工具简介
      • 3.2.签名流程
    • 4. keystore-explorer
      • 4.1.keystore-explorer安装及升级
    • 5. signerapk.jar签名
    • 6. 证书和公私钥
    • 7. 生成keystore

1.签名文件格式

常见的密钥库(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

还有一个*.keystoreEclipse打包生成的签名

2. 生成上传密钥和密钥库

点击查看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,不然可能被提示安装未完成。

3. apksigner签名

3.1. 签名工具简介

以下是搜集的一些简介:

  1. 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包进行签名.
  1. V1和V2签名的区别
在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以下版本
  1. zipalign和V2签名
位于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签名之前执行!!!

3.2.签名流程

Android StudioDebug时,对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'
        }
    }
  1. 打开cmd,把目录切换到SDKbuild-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

  1. 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就可能出现此问题。

4. keystore-explorer

直接使用 android studio生成上传密钥和密钥库, 在android中加载时,会抛出异常: load BKS error:wrong version of key store

4.1.keystore-explorer安装及升级

keystore-explorer下载地址,将keystore-explorer安装包下载后,双击安装完成。

然后第一次以管理员权限打开,默认会弹出提示框:
Android Protect-0.签名相关_第1张图片
–>点击Download Unlimited Strength ...下载更新包。
Android Protect-0.签名相关_第2张图片
再点击Browse to Unlimited ..选择刚下载的更新包,选中后,此时Upgrade按钮会变为可点,点击完成升级。
Android Protect-0.签名相关_第3张图片

不以管理员权限打开,升级会失败,因为要把升级包解压并拷贝到C盘安装目录下(C:\Program Files (x86)\KeyStore Explorer\lib)。

5. signerapk.jar签名

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

6. 证书和公私钥

证书和私钥官方文档

每个密钥都包含两个文件:一个是扩展名为 .x509.pem 的证书,另一个是扩展名为 .pk8(PCKS8) 的私钥。私钥需要加以保密,并用于对 apk 包进行签名。密钥本身也可能受密码保护。相比之下,证书只包含公开的一半密钥,因此可以大范围地分发。证书被用于验证某个 apk 包是否由相应的私钥进行签名。

Android签名中证书的格式采用X.509标准的版本三,不过省略了一些内容。可以通过keystore-explorer右键导出
Android Protect-0.签名相关_第4张图片
还可以把CERT.RSA改成CERT.p7b, 双击即可看到证书和公钥:
Android Protect-0.签名相关_第5张图片
X.509证书格式如下图所示:
Android Protect-0.签名相关_第6张图片
数字证书的格式普遍采用的是X.509V3国际标准,一个标准的X.509数字证书包含以下一些内容:

  1. 证书的版本信息;
  2. 证书的序列号,每个证书都有一个唯一的证书序列号;
  3. 证书所使用的签名算法;
  4. 证书的发行机构名称,命名规则一般采用X.500格式;
  5. 证书的有效期,通用的证书一般采用UTC时间格式,它的计时范围为1950-2049;
  6. 证书所有人的名称,命名规则一般采用X.500格式;
  7. 证书所有人的公开密钥;
  8. 证书发行者对证书的签名

Android Protect-0.签名相关_第7张图片
重要说明:编写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

7. 生成keystore

通过命令行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剖析)

你可能感兴趣的:(Android,Protect)