android 系统签名

归志宁无五亩园,读书本意在元元。这篇文章主要讲述android 系统签名相关的知识,希望能为你提供帮助。
本文转载自:http://blog.csdn.net/csh86277516/article/details/73549824
android— — 编译release版签名系统 AndroidManifest.xml中的android:sharedUserId="android.uid.system",代表的意思是和系统相同的uid,可以拥有修改系统时间,文件操作等权限。也有提到怎么单独给一个apk签名,这里补充一下Android的签名权限控制机制。
 
一:签名类型android的标准签名key有:
testkey
media
platform
shared
以上的四种,可以在源码的/build/target/product/security里面看到对应的密钥,其中shared.pk8代表私钥,shared.x509.pem公钥,一定是成对出现的。
其中testkey是作为android编译的时候默认的签名key,如果系统中的apk的android.mk中没有设置LOCAL_CERTIFICATE的值,就默认使用testkey。
而如果设置成:
LOCAL_CERTIFICATE := platform
就代表使用platform来签名,这样的话这个apk就拥有了和system相同的签名,因为系统级别的签名也是使用的platform来签名,此时使用android:sharedUserId="android.uid.system"才有用!
 
 
二:自定义签名Key在/build/target/product/security目录下有个README,里面有说怎么制作这些key以及使用问题(android4.2):
 

  1. The  following  commands  were  used  to  generate  the  test  key  pairs:   
  2.    
  3.     development/tools/make_key  testkey    ‘/C=US/ST=California/L=Mountain  View/O=Android/OU=Android/CN=Android/emailAddress=[email  protected]‘   
  4.     development/tools/make_key  platform  ‘/C=US/ST=California/L=Mountain  View/O=Android/OU=Android/CN=Android/emailAddress=[email  protected]‘   
  5.     development/tools/make_key  shared      ‘/C=US/ST=California/L=Mountain  View/O=Android/OU=Android/CN=Android/emailAddress=[email  protected]‘   
  6.     development/tools/make_key  media        ‘/C=US/ST=California/L=Mountain  View/O=Android/OU=Android/CN=Android/emailAddress=[email  protected]‘   
  7.    
  8. The  following  standard  test  keys  are  currently  included:   
  9.    
  10. testkey  --  a  generic  key  for  packages  that  do  not  otherwise  specify  a  key.   
  11. platform  --  a  test  key  for  packages  that  are  part  of  the  core  platform.   
  12. shared  --  a  test  key  for  things  that  are  shared  in  the  home/contacts  process.   
  13. media  --  a  test  key  for  packages  that  are  part  of  the  media/download  system.   
  14.    
  15. These  test  keys  are  used  strictly  in  development,  and  should  never  be  assumed   
  16. to  convey  any  sort  of  validity.    When  $BUILD_SECURE=true,  the  code  should  not   
  17. honor  these  keys  in  any  context.   

从上面可以看出来在源码下的/development/tools目录下有个make_key的脚本,通过传入两个参数就可以生成一对签名用的key。
 
其中第一个为key的名字,一般都默认成android本身有的,因为很多地方都默认使用了这些名字,我们自定义的话只需要对第二个参数动手脚,定义如下:
C ---> Country Name (2 letter code)
ST ---> State or Province Name (full name)
L ---> Locality Name (eg, city)
O ---> Organization Name (eg, company)
OU ---> Organizational Unit Name (eg, section)
CN ---> Common Name (eg, your name or your server’ s hostname)
emailAddress ---> Contact email address
另外在使用上面的make_key脚本生成key的过程中会提示输入password,我的处理是不输入,直接enter,不要密码!后面解释,用自定义的key替换/security下面的。
可以看到android源码里面的key使用的第二个参数就是上面README里面的,是公开的,所以要release版本的系统的话,肯定要有自己的签名key才能起到一个安全控制作用。
 
 
三:修改系统默认签名key在上面提到如果apk中的编译选项LOCAL_CERTIFICATE没有设置的话,就会使用默认的testkey作为签名key,我们可以修改成自己想要的key,按照上面的步骤制作一个releasekey,修改android配置在/build/core/config.mk中定义变量:
 
 
  1. DEFAULT_SYSTEM_DEV_CERTIFICATE  :=  build/target/product/security/releasekey   

在主makefile文件里面:
 
 
  1. ifeq  ($(DEFAULT_SYSTEM_DEV_CERTIFICATE),build/target/product/security/releasekey)   
  2. BUILD_VERSION_TAGS  +=  release-keys   
这样的话默认的所有签名将会使用releasekey。
  修改完之后就要编译了,如果上面的这些key在制作的时候输入了password就会出现如下错误:
   
  1. Enter  password  for  build/target/product/security/releasekey.pk8  (password  will  not  be  hidden):  java.lang.NullPointerException   
  2.         at  com.android.signapk.SignApk.decryptPrivateKey(SignApk.java:142)   
  3.         at  com.android.signapk.SignApk.readPrivateKey(SignApk.java:166)   
  4.         at  com.android.signapk.SignApk.main(SignApk.java:531)   
  5. Enter  password  for  build/target/product/security/releasekey.pk8  (password  will  not  be  hidden):  make:  ***  [out/target/product/gotechcn/obj/APPS/CalendarProvider_intermediates/package.apk]  错误  1   
  6. make:  ***  正在等待未完成的任务....   
  7. Enter  password  for  build/target/product/security/releasekey.pk8  (password  will  not  be  hidden):  java.lang.NullPointerException   
  8.         at  com.android.signapk.SignApk.decryptPrivateKey(SignApk.java:142)   
  9.         at  com.android.signapk.SignApk.readPrivateKey(SignApk.java:166)   
  10.         at  com.android.signapk.SignApk.main(SignApk.java:531)   
  11. make:  ***  [out/target/product/gotechcn/obj/APPS/Calculator_intermediates/package.apk]  错误  1   
  12. Warning:  AndroidManifest.xml  already  defines  minSdkVersion  (in  http://schemas.android.com/apk/res/android);   using  existing  value  in  manifest.   
  13. Warning:  AndroidManifest.xml  already  defines  targetSdkVersion  (in  http://schemas.android.com/apk/res/android);   using  existing  value  in  manifest.   
  14.   ‘out/target/common/obj/APPS/Calendar_intermediates/classes.dex‘  as  ‘classes.dex‘...   
  15. Enter  password  for  build/target/product/security/releasekey.pk8  (password  will  not  be  hidden):  java.lang.NullPointerException   
  16.         at  com.android.signapk.SignApk.decryptPrivateKey(SignApk.java:142)   
  17.         at  com.android.signapk.SignApk.readPrivateKey(SignApk.java:166)   
  18.         at  com.android.signapk.SignApk.main(SignApk.java:531)   
  19. make:  ***  [out/target/product/gotechcn/obj/APPS/Calendar_intermediates/package.apk]  错误  1   
  20. ^Cmake:  ***  [out/target/product/gotechcn/obj/APPS/BasicDreams_intermediates/package.apk]  错误  130   
 
我在网上找到了合理的解释:
其实会出现这个错误的最根本的原因是多线程的问题。在编译的时候为了加速一般都会执行make -jxxx,这样本来需要手动输入密码的时候,由于其它线程的运行,就会导致影响当前的输入终端,所以就会导致密码无法输入的情况!
再编译完成之后也可以在build.prop中查看到变量:
 
  1. ro.build.tags=release-keys   

这样处理了之后编译出来的都是签名过的了,系统才算是release版本
我发现我这样处理之后,整个系统的算是全部按照我的要求签名了。
 
四:其它网上看到还有另外的签名release办法,但是应该是针对另外的版本的,借用学习一下: 
 
  1. make  -j4  PRODUCT-product_modul-user  dist   


这个怎么跟平时的编译不一样,后面多了两个参数PRODUCT-product_modul-user 和 dist. 编译完成之后回在源码/out/dist/目录内生成个product_modul-target_files开头的zip文件.这就是我们需要进行签名的文件系统.
   
我的product_modul 是full_gotechcn,后面加“ -user” 代表的是最终用户版本,关于这个命名以及product_modul等可参考http://blog.csdn.net/jscese/article/details/23931159
【android 系统签名】 
编译出需要签名的zip压缩包之后,就是利用/security下面的准备的key进行签名了:
   
  1. ./build/tools/releasetools/sign_target_files_apks  -d  /build/target/product/security    out/dist/full_gotechcn-target_files.zip      out/dist/signed_target_files.zip   

签名目标文件 输出成signed_target_files.zip
 
如果出现某些apk出错,可以通过在full_gotechcn-target_files.zip前面加参数"-e < apkname> =" 来过滤这些apk.
然后再通过image的脚本生成imag的zip文件,这种方式不适用与我目前的工程源码,没有做过多验证!
 
 
 
 
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的方法。

    推荐阅读