Android签名机制可划分为两部分:(1)ROM签名机制;(2)第三方APK签名机制。
Android APK实际上是一个jar包,而jar包又是一个zip包。APK包的签名实际上使用的是jar包的签名机制:在zip中添加一个META的子目录,其中存放签名信息;而签名方法是为zip包中的每个文件计算其HASH值,得到签名文件(*.sf),然后对签名文件(.sf)进行签名并把签名保存在签名块文件(*.dsa)中。
ROM签名机制
在编译Android源码生成ROM的过程中,会使用build/target/product/security目录中的4个key(media, platform, shared, testkey)来对apk进行签名。其中,*.pk8是二进制形式(DER)的私钥,*.x509.pem是对应的X509公钥证书(BASE64编码)。build/target/product/security目录中的这几个默认key是没有密码保护的,只能用于debug版本的ROM。
要生成Release版本的ROM,可先生成TargetFiles,再使用带密码的key对TargetFiles重新签名,最后由重签名的TargetFiles来生成最终的ROM。
可以使用Android源码树中自带的工具“development/tools/make_key”来生成带密码的RSA公私钥对(实际上是通过openssl来生成的):
$ development/tools/make_key media ‘/C=CN/ST=Sichuan/L=Chengdu/O=MyOrg/OU=MyDepartment/CN=MyName’
上面的命令将生成一个二进制形式(DER)的私钥文件“media.pk8”和一个对应的X509公钥证书文件“media.x509.pem”。其中,/C表示“Country Code”,/ST表示“State or Province”,/L表示“City or Locality”,/O表示“Organization”,/OU表示“Organizational Unit”,/CN表示“Name”。前面的命令生成的RSA公钥的e值为3,可以修改development/tools/make_key脚本来使用F4 (0×10001)作为e值(openssl genrsa的-3参数改为-f4)。
也可以使用JDK中的keytool来生成公私钥对,第三方APK签名一般都是通过keytool来生成公私钥对的。
可以使用openssl x509命令来查看公钥证书的详细信息:
$ openssl x509 -in media.x509.pem -text -noout
or,
$ openssl x509 -in media.x509.pem -inform PEM -text -noout
还可以使用JDK中的keytool来查看公钥证书内容,但其输出内容没有openssl x509全面:
$ keytool -printcert -v -file media.x509.pem
有了key之后,可以使用工具“build/tools/releasetools/sign_target_files”来对TargetFiles重新签名:
$ build/tools/releasetools/sign_target_files_apks -d new_keys_dir -o target_files.zip target_files_resigned.zip
其中,new_keys_dir目录中需要有四个key(media, platform, shared, releasekey)。注意:这里的releasekey将代替默认的testkey(请参考build/tools/releasetools/sign_target_files脚本实现),也就是说,如果某个apk的Android.mk文件中的LOCAL_CERTIFICATE为testkey,那么在生成TargetFiles时是使用的build/target/product/security/testkey来签名的,这里重新签名时将使用new_keys_dir/releasekey来签名。
build/tools/releasetools/sign_target_files_apks是通过host/linux-x86/framework/signapk.jar来完成签名的。也可以直接使用host/linux-x86/framework/signapk.jar来对某个apk进行签名:
$ java -jar signapk [-w] publickey.x509[.pem] privatekey.pk8 input.jar output.jar
其中,”-w”表示还对整个apk包(zip包)进行签名,并把签名放在zip包的comment中。
第三方APK签名机制
对于第三方应用开发者而言,对APK签名相对要简单得多。第三方应用开发一般采用JDK中的keytool和jarsigner来完成签名密钥的管理和APK的签名。
使用keytool来生成存储有公私钥对的keystore:
$ keytool -genkey -v -keystore my-release-key.keystore -alias mykey -keyalg RSA -keysize 2048 -validity 10000
查看生成的密钥信息:
$ keytool -list -keystore my-release-key.keystore -alias mykey -v
or,
$ keytool -list -keystore my-release-key.keystore -alias mykey -rfc
(注:获取Base64格式的公钥证书,RFC 1421)
导出公钥证书:
$ keytool -export -keystore mystore -alias mykey -file my.der
(注:二进制格式公钥证书,DER)
$ keytool -export -keystore mystore -alias mykey -file my.pem -rfc
(注:Base64格式公钥证书,PEM)
对APK进行签名:
$ jarsigner -verbose -keystore my-release-key.keystore my_application.apk mykey
验证签名:
$ jarsigner -verify -verbose -certs my_application.apk
在进行Android二次开发时,有时需要把build/target/product/security下面的公私钥对转换为keystore的形式,可以参考这篇文章:把Android源码中的密码对转换为keystore的方法。