应用签名,APK签名对比及说明
分类:计算机编程

转发请注脚出入谢谢!

Android代码完整性校验

发布过Android应用的敌人们应当都知道,Android APK的发布是内需具名的。签字机制在Android应用和框架中有着特别最首要的效应。

转发要求有名出处:

图片 1下一步后要求填写应用签字图片 2那可难倒了自身了..签字keystore文件可不曾如此轻便."开荒者能够动用签字工具直接从安装当前应用的无绳话机中获得"查找文书档案,依照这么些页面提供的二个工具 具名生成工具

Android签名机制

譬如说,Android系统禁绝更新安装签字不雷同的APK;如若使用要求使用system权限,必得确定保障APK签字与Framework签字一致,等等。在《APK Crack》一文中,大家询问到,要破解二个APK,必然需求再度对APK举行签名。而那么些具名,通常景观非常小概再与APK原先的签订保持一致。(除非APK原来的书文者的私钥泄漏,那已是另二个档次的软件安全难点了。)

http://blog.csdn.net/lowprofile_coding/article/details/78004224

Android能源下载开采工具包开采第三方应用所急需的库以至文件。点击下载表率代码包涵了一个全体的楷模工程。该模范的应用能够参阅Android平台上手指南:HelloWeixin@Android。点击下载

    为了印证APK签字比对对软件安全的实用,我们有须要精通一下Android APK的签名机制。为了更便于大家知晓,大家从Auto-Sign工具的一条批管理命令聊到。

轻巧易行地说,签字机制评释了APK的批发机构。因而,站在软件安全的角度,我们就可以透过比对APK的具名意况,剖断此APK是还是不是由“官方”发行,实际不是被破解篡改过重新签字打包的“盗版软件”。

后面写过微信登四分享支付第一版:

签定生成工具用于获取安装到手机的第三方使用具名的apk包。点击下载

    大家理解到,要签定三个并未有签字过的APK,能够利用贰个叫作Auto-sign的工具。Auto-sign工具实际运作的是一个名字为Sign.bat的批管理命令。用文件编辑器展开这些批管理公事,大家得以发掘,达成签订合同作用的指令主假设这一行命令:

Android签字机制
    为了求证APK具名比对对软件安全的有效,大家有供给明白一下Android APK的签订协议机制。为了更便于大家了解,大家从Auto-Sign工具的一条批管理命令聊起。

http://blog.csdn.net/lowprofile_coding/article/details/48086381

能够叁个字符串,类似于:应用签字:049a9fde46bfc5087f3825582208b248安装那么些应用能够获得本手提式有线话机已经安装的有些android软件,依照软件的包名,类似于: com.demo.AppX 来搜索这一个软件,以至获得那一个软件的 应用签名。还恐怕有四个工具是在 获取签字.apk ,这几个也得以获得,然而作者测量试验发掘,只好突显一部分的本机应用,有个别应用查不到,就麻烦了..所以依旧用wechart的十一分吧.缺憾的是,Tencent何以不把七个小工具源码也产生来吧??

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

在《APK Crack》一文中,我们询问到,要签名四个从未签订过的APK,能够行使贰个叫作Auto-sign的工具。Auto-sign工具实际运维的是一个称呼Sign.bat的批管理命令。用文件编辑器展开这些批管理文件,大家能够开采,完毕签订公约功效的通令首若是这一行命令:

前言

绝大比非常多的app都有对接第三方sdk的急需。举例第三方登陆须要衔接微信、QQ、今日头条。第三方支付供给衔接微信、支付宝、银行职员联合会。

那个笔者都有利用过,都有利用过她们的sdk,认为最费劲的正是微信,不可能直接调节和测量试验,得用正式的签定进行签订左券技能调解。还或者有他们官方的demo也是跑不起来的,因为从没签字文件。供给专一的地点也很多。

微信开放平台 文书档案:

    那条命令的意义是:通过signapk.jar那个可推行jar包,以“testkey.x509.pem”那么些公钥文件和“testkey.pk8”这几个私钥文件对“update.apk”举办签订契约,签字后的文书保留为“update_signed.apk”。

 

代码达成

微信sdk今后补助Android Studio在线援用了,在此以前都以增添jar的点子。需求拜见微信的接口获取客户音信,所以把大家前边封装的okhttp也一齐在线援用。okhttp需求在自定义的Application中初步化那几个本人就不贴代码了。在此之前曾经讲过很频仍。在app/build.gradle文件dependencies标签中投入以下两行代码:

compile 'com.tencent.mm.opensdk:wechat-sdk-android-without-mta: 'compile 'com.ansen.http:okhttpencapsulation:1.0.1'

内需用到网络,所以在AndroidManifest.xml文件中出席网络权限:

<uses-permission android:name="android.permission.INTERNET" />

activity_main.xml

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:andro android:layout_width="match_parent" android:layout_height="match_parent" android:padding="10dp" android:orientation="vertical"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="登录之后信息在这里显示"/> <RelativeLayout android:layout_width="wrap_content" android:layout_height="wrap_content"> <TextView android: android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="昵称:"/> <TextView android: android:layout_below="@ id/tv_nickname" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="年龄:"/> </RelativeLayout> <Button android: android:layout_width="match_parent" android:layout_height="wrap_content" android:text="微信登录"/> <Button android: android:layout_width="match_parent" android:layout_height="wrap_content" android:text="分享到朋友圈"/> <Button android: android:layout_width="match_parent" android:layout_height="wrap_content" android:text="分享给好友"/> <Button android: android:layout_width="match_parent" android:layout_height="wrap_content" android:text="微信支付"/></LinearLayout>

布局文件很简短,就LinearLayout里面放了多少个TextView,跟多少个按键。

WeiXin.java 用于伊芙ntBus来传送消息,微信sdk有个很奇异的地点,就是不论登入、共享、支付之后都得用一个Activity来接受,所以大家还得从接收的百般activity把结果音信透过EventBus传递给MainActivity。固然用广播也能落到实处,不过个人喜欢用EventBus,使用灵活。容易轻量。

public class WeiXin { private int type;//1:登录 2.分享 3:微信支付 private int errCode;//微信返回的错误码 private String code;//登录成功才会有的code public WeiXin() { } public WeiXin(int type,int errCode, String code) { this.type = type; this.errCode=errCode; this.code = code; } public int getType() { return type; } public void setType { this.type = type; } public String getCode() { return code; } public void setCode(String code) { this.code = code; } public int getErrCode() { return errCode; } public void setErrCode(int errCode) { this.errCode = errCode; }}

Constant.java 常量类,微信appid跟secret的值用多个常量保存。为了爱戴隐秘那七个值小编曾经修改过。

public class Constant { public static String WECHAT_APPID="wxda6db2aec81389af"; public static String WECHAT_SECRET="8fed5a2d510022587ef8a6194c965be3";}

MainActivity.java 全体代码贴出来比较乱,临时贴出MainActivity部分代码。

public class MainActivity extends AppCompatActivity implements View.OnClickListener { private IWXAPI wxAPI; private TextView tvNickname,tvAge; public static final int IMAGE_SIZE=32768;//微信分享图片大小限制 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); EventBus.getDefault().register;//注册 wxAPI = WXAPIFactory.createWXAPI(this,Constant.WECHAT_APPID,true); wxAPI.registerApp(Constant.WECHAT_APPID); findViewById(R.id.btn_login).setOnClickListener; findViewById(R.id.btn_share_friend_circle).setOnClickListener; findViewById(R.id.btn_share_friend).setOnClickListener; findViewById(R.id.btn_pay).setOnClickListener; tvNickname=  findViewById(R.id.tv_nickname); tvAge= findViewById(R.id.tv_age); } @Override public void onClick(View view) { switch (view.getId{ case R.id.btn_login://微信登录 login(); break; case R.id.btn_share_friend_circle://微信分享到朋友圈 share; break; case R.id.btn_share_friend://微信分享给朋友 share; break; case R.id.btn_pay://微信支付// 先去服务器获取支付信息,返回一个WeiXinPay对象,然后调用pay方法 showToast("微信支付需要服务器支持"); break; } } /** * 这里用到的了EventBus框架 * @param weiXin */ @Subscribe public void onEventMainThread(WeiXin weiXin){ Log.i("ansen","收到eventbus请求 type:" weiXin.getType; if(weiXin.getType{//登录 getAccessToken(weiXin.getCode; }else if(weiXin.getType{//分享 switch (weiXin.getErrCode{ case BaseResp.ErrCode.ERR_OK: Log.i("ansen", "微信分享成功....."); break; case BaseResp.ErrCode.ERR_USER_CANCEL://分享取消 Log.i("ansen", "微信分享取消....."); break; case BaseResp.ErrCode.ERR_AUTH_DENIED://分享被拒绝 Log.i("ansen", "微信分享被拒绝....."); break; } }else if(weiXin.getType{//微信支付 if(weiXin.getErrCode()==BaseResp.ErrCode.ERR_OK){//成功 Log.i("ansen", "微信支付成功....."); } } } .......... public void showToast(String message){ Toast.makeText(this,message,Toast.LENGTH_LONG).show(); } @Override protected void onDestroy() { super.onDestroy(); EventBus.getDefault().unregister;//取消注册 }}
  • onCreate 注册EventBus,通过WXAPIFactory创建IWXAPI类,并且注册appid,给多少个按键按键设置点击事件。查找显示名字跟年龄的多个TextView。
  • onClick 点击事件监听,根据id来推断点击不一致的按键,跳转到相应的秘籍,那一个点子没贴出来来,等会单独讲。
  • onEventMainThread(WeiXin weiXin) 用来接受消息,那几个办法有个参数,用来推断项目,正是大家用EventBus发送时参数必需是WeiXin类型。首先剖断type,是登入依然分享依旧支付。登陆成功景观下会收获到code,依据code然后大家就会博取到微信客户音信。
  • showToast Toast提示
  • onDestroy 取消EventBus注册

微信登陆

微信登陆流程有以下多少个步骤:

  • 微信授权登录
  • 依据授权登入code 获取该客商token
  • 基于token获取客户资料

当我们点击登入按键的时候,调用的是login方法。这些方式就在MainActivity中间。正是给微信发起一个签到央求,弹出一个授权分界面。

public void login(){ SendAuth.Req req = new SendAuth.Req(); req.scope = "snsapi_userinfo"; req.state = String.valueOf(System.currentTimeMillis; wxAPI.sendReq;}

在你的包名相应目录下新建三个wxapi目录,然后在wxapi目录下增加产量二个WXEntryActivity类,用来收纳登入授权以致享受时微信的回调消息。这一个类承袭自Activity,要求达成IWXAPIEventHandler接口。

package com.ansen.shoenet.wxapi;public class WXEntryActivity extends Activity implements IWXAPIEventHandler { private IWXAPI wxAPI; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); wxAPI = WXAPIFactory.createWXAPI(this,Constant.WECHAT_APPID,true); wxAPI.registerApp(Constant.WECHAT_APPID); wxAPI.handleIntent(getIntent; } @Override protected void onNewIntent(Intent intent){ super.onNewIntent; wxAPI.handleIntent(getIntent; Log.i("ansen","WXEntryActivity onNewIntent"); } @Override public void onReq(BaseReq arg0) { Log.i("ansen","WXEntryActivity onReq:" arg0); } @Override public void onResp(BaseResp resp){ if(resp.getType()== ConstantsAPI.COMMAND_SENDMESSAGE_TO_WX){//分享 Log.i("ansen","微信分享操作....."); WeiXin weiXin=new WeiXin(2,resp.errCode,""); EventBus.getDefault().post; }else if(resp.getType()==ConstantsAPI.COMMAND_SENDAUTH){//登陆 Log.i("ansen", "微信登录操作....."); SendAuth.Resp authResp = (SendAuth.Resp) resp; WeiXin weiXin=new WeiXin(1,resp.errCode,authResp.code); EventBus.getDefault().post; } finish(); }}

onCreate、onNewIntent、onReq那多个艺术是定点写法。onResp方法接收微信结果音信,首先判别项目,依据分化的种类去封装WeiXin对象,假使是登入操作,把code传入进去,然后把包裹好的WeiXin对象通过EventBus发送出去。MainActivity的on伊芙ntMainThread方法就能够吸收接纳到这几个音讯。最终调用finish关闭当前的activity。

WXEntryActivity记得在AndroidManifest.xml中注册

<activity android:exported="true" android:name=".wxapi.WXEntryActivity"/>

继续回到首页的onEventMainThread,假若登入类型调用getAccessToken(),何况传入code。根据code获取access_token,这些url是微信公开的,供给传入八个参数,appid、secret、code。央浼成功之后会回到access_token跟openid等信息。

public void getAccessToken(String code){ String url = "https://api.weixin.qq.com/sns/oauth2/access_token?"   "app&secret=" Constant.WECHAT_SECRET  "&code=" code "&grant_type=authorization_code"; HTTPCaller.getInstance().get(WeiXinToken.class, url, null, new RequestDataCallback<WeiXinToken>() { @Override public void dataCallback(WeiXinToken obj) { if(obj.getErrcode{//请求成功 getWeiXinUserInfo; }else{//请求失败 showToast(obj.getErrmsg; } } });}

获取到access_token跟openid之后继续调用getWeiXinUserInfo方法获取客户音讯。那样就会取到当前微信app登入的客户一些音讯。有外号、年龄、头像地址、语言等宗旨消息。在店堂支付中,到了这一步就足以拿着那一个音讯调用自身服务器的登陆接口。当然大家这边就把外号跟年龄给TextView展现下。

public void getWeiXinUserInfo(WeiXinToken weiXinToken){ String url = "https://api.weixin.qq.com/sns/userinfo?access_token="  weiXinToken.getAccess_token() "&open昵称:" obj.getNickname; tvAge.setText("年龄:" obj.getAge; Log.i("ansen","头像地址:" obj.getHeadimgurl;}

WeiXinToken跟WeiXinInfo那四个实体类就不贴代码了,WeiXinToken用来映射获取访谈token接口重回的json。WeiXinInfo用来映射获取客商接口再次回到的json。

微信分享

分享有三种享受到对象圈跟分享给亲密的朋友,统一调用share方法。传入三个boolean类型来剖断是不是分享到对象圈。

public void share(boolean friendsCircle){ WXWebpageObject webpage = new WXWebpageObject(); webpage.webpageUrl = "www.baidu.com";//分享url WXMediaMessage msg = new WXMediaMessage; msg.title = "分享标题"; msg.description = "分享描述"; msg.thumbData =getThumbData();//封面图片byte数组 SendMessageToWX.Req req = new SendMessageToWX.Req(); req.transaction = String.valueOf(System.currentTimeMillis; req.message = msg; req.scene = friendsCircle ? SendMessageToWX.Req.WXSceneTimeline : SendMessageToWX.Req.WXSceneSession; wxAPI.sendReq;}

享用内容有不菲格式,分享图片、分享录制、分享音讯。大家那边就享受音讯为例,也是分享相比宽泛的格式。首先new二个WXWebpageObject对象,设置标题、内容、展开链接、封面等。最终调用wxAPI的sendReq放松叁个呼吁。

享用跟登入一样,都会回调WXEntryActivity,然后又把分享结果发送给MainActivity.onEventMainThread方法。

支付开垦第一须要央求大家友好的服务器,获取支付音讯。获取成功之后调用pay方法。

public void pay(WeiXinPay weiXinPay){ PayReq req = new PayReq(); req.appId = Constant.WECHAT_APPID;//appid req.nonceStr=weiXinPay.getNoncestr();//随机字符串,不长于32位。推荐随机数生成算法 req.packageValue=weiXinPay.getPackage_value();//暂填写固定值Sign=WXPay req.sign=weiXinPay.getSign();//签名 req.partnerId=weiXinPay.getPartnerid();//微信支付分配的商户号 req.prepayId=weiXinPay.getPrepayid();//微信返回的支付交易会话ID req.timeStamp=weiXinPay.getTimestamp();//时间戳 wxAPI.registerApp(Constant.WECHAT_APPID); wxAPI.sendReq;}

weiXinPay的值应该是大家从本身服务器获取的,然后把重回音讯打包到PayReq对象中,最终调用wxAPI的sendReq方法发起呼吁。

在wxapi目录下增加产量三个WXPayEntryActivity类,那一个类跟WXEntryActivity同级,用来接收微信支付的回调消息。这些类承袭自Activity,要求完结IWXAPI伊夫ntHandler接口。

public class WXPayEntryActivity extends Activity implements IWXAPIEventHandler { private IWXAPI wxAPI; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); wxAPI = WXAPIFactory.createWXAPI(this, Constant.WECHAT_APPID); wxAPI.handleIntent(getIntent; } @Override protected void onNewIntent(Intent intent){ super.onNewIntent; setIntent; wxAPI.handleIntent(intent, this); } @Override public void onReq(BaseReq baseReq) {} @Override public void onResp(BaseResp resp) { Log.i("ansen", "微信支付回调 返回错误码:" resp.errCode " 错误名称:" resp.errStr); if (resp.getType() == ConstantsAPI.COMMAND_PAY_BY_WX){//微信支付 WeiXin weiXin=new WeiXin(3,resp.errCode,""); EventBus.getDefault().post; } finish(); }}

其他艺术都是定点写法,在onResp中剖断假设是微信登陆,就封装一个WeiXin对象,然后发送伊夫ntBus要求。那样MainActivity的onEventMainThread就能够抽出到那几个WeiXin对象。

WXPayEntryActivity记得在AndroidManifest.xml中注册。

<activity android:exported="true" android:name=".wxapi.WXPayEntryActivity"/>

品类组织图如下所示,从图中我们看出软件包名是com.ansen.shoenet。接收微信登陆支付再次来到的Activity的包名必得是com.ansen.shoenet.wxapi。几个activity的名字也是永久写法。

图片 3project_structure

Signature的改动方法[java.security类 Signature]

    对于此处所使用的私钥和公钥的扭转格局,这里就不做越发介绍了。这上边的材料大家能够找到比相当多。大家这里要讲的是signapk.jar到底做了哪些。

    java -jar signapk.jar testkey.x509.pem testkey.pk8 update.apk update_signed.apk
    那条命令的意思是:通过signapk.jar这几个可举行jar包,以“testkey.x509.pem”这么些公钥文件和“testkey.pk8”这些私钥文件对“update.apk”实行具名,签字后的公文物保护留为“update_signed.apk”。 
    对于此处所利用的私钥和公钥的变型方式,这里就不做更加的介绍了。这上边的素材大家能够找到非常多。大家这里要讲的是signapk.jar到底做了怎么着。

签名

微信登五分享支付都有叁个签订合同验证,那几个很辛勤,导致每趟调节和测量试验都需求再一次具名。

首先用android studio生成四个规范的具名文件,签字文件是.jks结尾的,这么些签名文件是你今后打线上包直接要用到的。然后用这么些签字文件生成apk。这一年大家的app就有了业内签订协议。把正规化具名的apk发送到手提式有线电话机上扩充设置。

再正是下载一个签订合同生成工具安装,那么些工具用于获取安装到手机的第三方使用具名的apk包。微信官方下载地址:

https://res.wx.qq.com/open/zh_CN/htmledition/res/dev/download/sdk/Gen_Signature_Android2.apk

上述五个app都设置好了后头展开从微信下载的不胜app,软件名字叫「GenSignature」,有七个输入框,输入大家软件的包名,点击Get Signature按键.效果图如下:

图片 4get_signature

把这行暗绛红的16进制数炒下来保存到txt文本中。

Android获取应用程序消息列表:

    signapk.jar是Android源码包中的贰个签定工具。由于Android是个开源项目,所以,很喜欢地,我们得以一直找到signapk.jar的源码!路线为/build/tools/signapk/SignApk.java。

    signapk.jar是Android源码包中的三个签名工具。由于Android是个开源项目,所以,很欢乐地,大家能够直接找到signapk.jar的源码!路线为/build/tools/signapk/SignApk.java。

微信sdk官方网站后台配置

官方网址地址:

https://open.weixin.qq.com/

在微信sdk首页,有个管理核心点击之后私下认可正是移动应用,假诺还尚未开创移动应用就先创造三个,借使有了就点击当前的行使后边的查阅开关,就能进去应用详细分界面。

在选择详细分界面从来往下滚动,滚到最底部有个开辟信息。点击修改,步向修改分界面,在改造分界面滚动到最上面,效果图如下所示:

图片 5app_info

第一大家在Android应用这里打上勾,然后填写应用签名,这几个签字都以自个儿事先要你们保存到记事本上的要命值,包名便是app包名。点击保存。

对待八个尚未签名的APK和三个签名好的APK,大家会发掘,具名好的APK包中多了二个名字为META-INF的文书夹。里面有八个文件,分外号叫MANIFEST.MF、CERT.SF和CERT.ENCORESA。signapk.jar就是生成了那多少个文本(其余文件未有别的改造。由此大家得以很轻松去掉原有具名新闻)。

比较二个未曾签订的APK和一个签定好的APK,大家会意识,具名好的APK包中多了叁个称作META-INF的文本夹。里面有八个文本,分外号字为MANIFEST.MF、CERT.SF和CERT.SportageSA。signapk.jar正是生成了那多少个文件(其余文件并未有另外改动。由此我们能够很轻巧去掉原有签字音信)。

运作软件

报到之后效果图如下:

图片 6login_success

享受到对象圈如下:

图片 7share_friend_circle

分享给相爱的人:

图片 8share_friend

微信支付没办法测量检验,因为急需服务器资助。

    通过阅读signapk源码,大家能够清理具名APK包的总体经过。

    通过阅读signapk源码,我们能够清理具名APK包的满贯经过。

微信官方开采文书档案

作者那偏小说只是对准未来微信的sdk版本接入,可是sdk是有望变动的,版本变化、接口变化等。所以提议我们照旧以法定文档为主。作者的稿子提供参照他事他说加以考察。

运动接纳微信登录开采指南

https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1&id=open1419317851&token=219192a54f13e8e7011ced8e4ce5b36b699629c4&lang=zh_CN

Android微信支付开辟手册

https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1&id=open1419317784&token=219192a54f13e8e7011ced8e4ce5b36b699629c4&lang=zh_CN

1、 生成MANIFEST.MF文件:

 

注意事项

联网微信sdk有不菲亟需小心的地点,这里咱们最后再来做一个总括。

  • 微信登录,分享,支付回调的Activity包名跟类名必定要严加遵守要求去写
  • 采用回调的是Activity一定要在AndroidManifest.xml中中注册
  • Constant里面多少个常量的值要去微信报名并且制造应用才有的,这里须求改成你们申请的值。
  • 急需走访互联网所以记得在AndroidManifest.xml中增多权限
  • 调用微信的登陆,分享,支付你的安装包供给求有具名,具名消息必需求跟你在微信官互连网配置的签订新闻同样
  • 微信没有客服支持.....要是出了难点看官方的德姆o或然官方API
  • 微信SDK日常晋级,就算你付出的时候有流行的就用时髦的吧.....

前后相继遍历update.apk包中的全体文件(entry),对非文件夹非签字文件的公文,每一种生成SHA1的数字签字音讯,再用Base64举行编码。具体代码见这些措施:

1、 生成MANIFEST.MF文件:

提及底的末尾

你们一贯运转小编的demo是非凡的,因为你们未有的jks文件,没有办法签字,何况源码中的appid跟secret被自个儿修改过了,是无法应用的,不过你们只怕又想看运营作效果果,所以笔者在等级次序下建了个apk文件夹,里面放了七个能够测验微信登四分享的apk安装包。

源码下载

若是你想第有的时候间看笔者的末代小说,扫码关怀大伙儿号,周周不定期推送Android开荒实战教程小说...

 Android开发666 - 安卓开发技术分享 扫描二维码加关注

图片 9Android开发666

    private static Manifest addDigestsToManifest(JarFile jar)

程序遍历update.apk包中的全体文件(entry),对非文件夹非签字文件的文书,每个生成SHA1的数字具名音讯,再用Base64进行编码。具体代码见那个办法:

根本代码如下:

 

[objc] view plain copy

    private static Manifest addDigestsToManifest(JarFile jar)
一言九鼎代码如下:

for (JarEntry entry : byName.values()) {  

 1     for (JarEntry entry: byName.values()) {
 2         String name = entry.getName();
 3         if (!entry.isDirectory() && !name.equals(JarFile.MANIFEST_NAME) &&
 4             !name.equals(CERT_SF_NAME) && !name.equals(CERT_RSA_NAME) &&
 5                (stripPattern == null ||!stripPattern.matcher(name).matches())) {
 6                 InputStream data = jar.getInputStream(entry);
 7                 while ((num = data.read(buffer)) > 0) {
 8                     md.update(buffer, 0, num);
 9                 }
10                 Attributes attr = null;
11                 if (input != null) attr = input.getAttributes(name);
12                 attr = attr != null ? new Attributes(attr) : new Attributes();
13                 attr.putValue("SHA1-Digest", base64.encode(md.digest()));
14                 output.getEntries().put(name, attr);
15           }
16     }

String name = entry.getName();  

    之后将转移的签名写入MANIFEST.MF文件。关键代码如下:

if (!entry.isDirectory() && !name.equals(JarFile.MANIFEST_NAME) && !name.equals(CERT_SF_NAME)  

 

&& !name.equals(CERT_RSA_NAME) && (stripPattern == null || !stripPattern.matcher(name).matches())) {  

1     Manifest manifest = addDigestsToManifest(inputJar);
2     je = new JarEntry(JarFile.MANIFEST_NAME);
3     je.setTime(timestamp);
4     outputJar.putNextEntry(je);
5     manifest.write(outputJar);
    这里差不离介绍下SHA1数字具名。轻便地说,它正是一种安全哈希算法,类似于MD5算法。它把自由长度的输入,通过散列算法变成固定长度的输出(这里我们誉为“摘要新闻”)。你无法仅通过那些摘要消息过来原本的消息。别的,它保险不相同音讯的摘要消息互相不一致。由此,借使您转移了apk包中的文件,那么在apk安装校验时,改动后的公文章摘要要音讯与MANIFEST.MF的侦察新闻差别,于是程序就无法不负职务安装。

InputStream data = jar.getInputStream(entry);  

2、 生成CERT.SF文件:

while ((num = data.read(buffer)) > 0) {  

对前一步生成的Manifest,使用SHA1-ENVISIONSA算法,用私钥举办签名。关键代码如下:

md.update(buffer, 0, num);  

1     Signature signature = Signature.getInstance("SHA1withRSA");
2     signature.initSign(privateKey);
3     je = new JarEntry(CERT_SF_NAME);
4     je.setTime(timestamp);
5     outputJar.putNextEntry(je);
6     writeSignatureFile(manifest,
7     new SignatureOutputStream(outputJar, signature));
    RAV4SA是一种非对称加密算法。用私钥通过LX570SA算法对摘要音信实行加密。在安装时只可以使用公钥技巧解密它。解密之后,将它与未加密的摘要消息实行自己检查自纠,假若适合,则注明内容并未有被那些修改。

        }  

3、 生成CERT.RSA文件:

        Attributes attr = null;  

生成MANIFEST.MF未有接纳密钥音信,生成CERT.SF文件使用了私钥文件。那么大家能够很轻便预计到,CERT.OdysseySA文件的扭转料定和公钥相关。

if (input != null)  

CERT.CRUISERSA文件中保留了公钥、所运用的加密算法等新闻。宗旨代码如下:

attr = input.getAttributes(name);  

 

attr = attr != null ?new Attributes(attr) : new Attributes();  

1     je = new JarEntry(CERT_RSA_NAME);
2     je.setTime(timestamp);
3     outputJar.putNextEntry(je);
4     writeSignatureBlock(signature, publicKey, outputJar);
    当中writeSignatureBlock的代码如下:

attr.putValue("SHA1-Digest", base64.encode(md.digest()));  

 

output.getEntries().put(name, attr);  

 1     private static void writeSignatureBlock(
 2         Signature signature, X509Certificate publicKey, OutputStream out)
 3             throws IOException, GeneralSecurityException {
 4                 SignerInfo signerInfo = new SignerInfo(
 5                 new X500Name(publicKey.getIssuerX500Principal().getName()),
 6                 publicKey.getSerialNumber(),
 7                 AlgorithmId.get("SHA1"),
 8                 AlgorithmId.get("RSA"),
 9                 signature.sign());
10 
11         PKCS7 pkcs7 = new PKCS7(
12             new AlgorithmId[] { AlgorithmId.get("SHA1") },
13             new ContentInfo(ContentInfo.DATA_OID, null),
14             new X509Certificate[] { publicKey },
15             new SignerInfo[] { signerInfo });
16 
17         pkcs7.encodeSignedData(out);
18     }
    好了,深入分析完APK包的签名流程,大家得以精通地开掘到:

    }  

1、 Android具名机制其实是对APK包完整性和揭橥单位独一性的一种校验机制。

}  

2、 Android具名机制不可能挡住APK包被修改,但修改后的再具名无法与原来的具名保持一致。(具备私钥的事态除了)。

    之后将转移的具名写入MANIFEST.MF文件。关键代码如下:

3、 APK包加密的公钥就打包在APK包内,且区别的私钥对应分化的公钥。换句话言之,分化的私钥具名的APK公钥也必不等同。所以大家能够依附公钥的比较,来判断私钥是或不是一律。

[objc] view plain copy

APK具名比对的兑现格局
    好了,通过Android签字机制的剖释,我们从理论上证实了通过APK公钥的比对能判别八个APK的公布单位。而且那一个布告单位是很难伪装的,大家有的时候能够感觉是不可伪装的。

Manifest manifest = addDigestsToManifest(inputJar);  

    有了辩驳基础后,大家就足以起先举行了。那么什么样赢得到APK文件的公钥消息吗?因为Android系统安装程序肯定会拿到APK音信进行比对,所以大家能够透过Android源码得到部分思路和支援。

je =new JarEntry(JarFile.MANIFEST_NAME);  

    源码中有一个隐形的类用于APK包的分析。这一个类叫PackageParser,路线为frameworksbasecorejavaandroidcontentpmPackageParser.java。当大家供给得到APK包的相干消息时,能够平昔动用那个类,下边代码就是三个事例函数:

je.setTime(timestamp);  

 

outputJar.putNextEntry(je);  

 1     private PackageInfo parsePackage(String archiveFilePath, int flags){
 2         
 3         PackageParser packageParser = new PackageParser(archiveFilePath);
 4         DisplayMetrics metrics = new DisplayMetrics();
 5         metrics.setToDefaults();
 6         final File sourceFile = new File(archiveFilePath);
 7         PackageParser.Package pkg = packageParser.parsePackage(
 8                 sourceFile, archiveFilePath, metrics, 0);
 9         if (pkg == null) {
10             return null;
11         }
12         
13         packageParser.collectCertificates(pkg, 0); 
14         
15         return PackageParser.generatePackageInfo(pkg, null, flags, 0, 0);
16     }
    在那之中参数archiveFilePath钦赐APK文件路线;flags需安装PackageManager.GET_SIGNATURES位,以担保重返证书签名音讯。

manifest.write(outputJar);  

    具体如何通过PackageParser获取签字音信在此处不做详述,具体代码请参见PackageParser中的public boolean collectCertificates(Package pkg, int flags)和private Certificate[] loadCertificates(JarFile jarFile, JarEntry je, byte[] readBuffer)方法。至于哪些在Android应用开辟中采纳隐蔽的类及方法,能够参见作者的那篇文章:《Android应用开辟中什么运用掩饰API》。

    这里大约介绍下SHA1数字具名。轻易地说,它正是一种安全哈希算法,类似于MD5算法。它把自由长度的输入,通过散列算法形成固定长度的出口(这里我们称为“摘要新闻”)。你无法仅经过那一个摘要音讯过来原本的音信。另外,它保障差别音信的摘要音讯交互分化。因而,假使您更改了apk包中的文件,那么在apk设置校验时,改换后的文书摘要音信与MANIFEST.MF的印证新闻差别,于是程序就不可能成功安装。

    紧接着,我们就足以经过packageInfo.signatures来拜会到APK的签字消息。还亟需验证的是 Android中Signature和Java中Certificate的应和关系。它们的涉嫌如上边代码所示:

2、 生成CERT.SF文件:

 

对前一步生成的Manifest,使用SHA1-WranglerSA算法,用私钥实行签名。关键代码如下:

1     pkg.mSignatures = new Signature[certs.length];
2     for (int i=0; i<N; i ) {
3         pkg.mSignatures[i] = new Signature(
4         certs[i].getEncoded());
5     }
    也正是说signature = new Signature(certificate.getEncoded()); certificate证书中隐含了公钥和证件的其他基本新闻。公钥分歧,证书肯定互分裂。大家得以通过certificate的getPublicKey方法获得公钥消息。所以比对签字证书本质上正是比对公钥消息。

[objc] view plain copy

    OK,获取到APK签名证书之后,就剩下比对了。这些简单,功用函数如下所示:

Signature signature = Signature.getInstance("SHA1withRSA");  

 1     private boolean IsSignaturesSame(Signature[] s1, Signature[] s2) {
 2             if (s1 == null) {
 3                 return false;
 4             }
 5             if (s2 == null) {
 6                 return false;
 7             }
 8             HashSet<Signature> set1 = new HashSet<Signature>();
 9             for (Signature sig : s1) {
10                 set1.add(sig);
11             }
12             HashSet<Signature> set2 = new HashSet<Signature>();
13             for (Signature sig : s2) {
14                 set2.add(sig);
15             }
16             // Make sure s2 contains all signatures in s1.
17             if (set1.equals(set2)) {
18                 return true;
19             }
20             return false;
21         }

signature.initSign(privateKey);  

APK具名比对的利用场景

je =new JarEntry(CERT_SF_NAME);  

    经过上述的演讲,想必我们已经精通具名比对的规律和自己的落实格局了。那么什么样时候怎样境况切合利用签字比较来维持Android APK的软件安全呢?

je.setTime(timestamp);  

    个人以为首要有以下三种处境:

outputJar.putNextEntry(je);  

1、 程序自检查评定。在程序运维时,自己实行签订公约比对。比对样本可以寄存在APK包内,也可寄存于云端。劣点是先后被破解时,自质量评定作用雷同恐怕境遇破坏,使其失效。

writeSignatureFile(manifest,new SignatureOutputStream(outputJar, signature));  

2、 可靠的第三方检查评定。由可相信任的第三方前后相继负责APK的软件安全难点。相比较样本由第三方搜集,放在云端。这种方法适用于杀毒安全软件只怕应用软件马克et之类的软件下载市镇。劣势是急需联网检查实验,在无网络状态下相当小概兑现效果与利益。(不或者把多量的具名数据放在移动器具本地)。

    TucsonSA是一种非对称加密算法。用私钥通过RAV4SA算法对摘要消息进行加密。在设置时不得不采纳公钥技巧解密它。解密之后,将它与未加密的摘要音讯进行比较,假使相符,则证明内容未有被非常修改。

3、 系统限虞诩装。那就关系到改Android系统了。限定仅能设置有个别证书的APK。软件发表商需求向系统一发布表上申请证书。若是发掘难点,能跟踪到是哪些软件公布商的义务。适用于系统提供商可能终端产品生产商。缺点是超负荷密封,不方便人民群众系统的开放性。

3、 生成CERT.RSA文件:

如上两种意况,尽管各有短处,但短处并不是不可能战胜的。举例,我们能够设想程序自检查实验的成效用native method的方法达成等等。软件安全部都以三个犬牙相制的课题,往往必要种种技巧协同使用,手艺越来越好的保持软件不被恶心破坏。

生成MANIFEST.MF未有选用密钥音讯,生成CERT.SF文件使用了私钥文件。那么大家得以很轻便估量到,CERT.路虎极光SA文件的改变肯定和公钥相关。

CERT.LANDSA文件中保留了公钥、所选用的加密算法等音信。核心代码如下:

[objc] view plain copy

je = new JarEntry(CERT_RSA_NAME);  

je.setTime(timestamp);  

outputJar.putNextEntry(je);  

writeSignatureBlock(signature, publicKey, outputJar);  

    此中writeSignatureBlock的代码如下:

[objc] view plain copy

private static void writeSignatureBlock(Signature signature, X509Certificate publicKey, OutputStream out)  

throws IOException, GeneralSecurityException {  

SignerInfo signerInfo =new SignerInfo(new X500Name(publicKey.getIssuerX500Principal().getName()),  

publicKey.getSerialNumber(), AlgorithmId.get("SHA1"), AlgorithmId.get("RSA"), signature.sign());  

PKCS7 pkcs7 = new PKCS7(new AlgorithmId[] { AlgorithmId.get("SHA1") },  

new ContentInfo(ContentInfo.DATA_OID, null), new X509Certificate[] { publicKey },  

new SignerInfo[] { signerInfo });  

pkcs7.encodeSignedData(out);  

}  

    好了,解析完APK包的签字流程,大家得以掌握地觉察到:

1、 Android签字机制其实是对APK包完整性和揭穿单位独一性的一种校验机制。

2、 Android具名机制不能够拦截APK包被修改,但修改后的再具名不能与原先的具名保持一致。(具有私钥的景观除了)。

3、 APK包加密的公钥就打包在APK包内,且差异的私钥对应不相同的公钥。换句话言之,区别的私钥签名的APK公钥也必差异。所以大家得以依靠公钥的自己检查自纠,来判别私钥是或不是一致。

APK签字比对的完毕格局

    好了,通过Android具名机制的剖释,大家从理论上表达了通过APK公钥的比对能看清多个APK的发表单位。何况那一个公告单位是很难伪装的,大家最近可以以为是不足伪装的。

    有了申辩功底后,大家就能够起来施行了。那么如何得到到APK文件的公钥消息呢?因为Android系统安装程序明确会拿走APK新闻举办比对,所以大家得以经过Android源码获得部分思路和帮忙。

    源码中有二个隐身的类用于APK包的深入分析。这么些类叫PackageParser,路径为frameworksbasecorejavaandroidcontentpmPackageParser.java。当大家供给获得APK包的连锁音讯时,能够直接选拔这几个类,上面代码就是二个例子函数:

[objc] view plain copy

private PackageInfo parsePackage(String archiveFilePath, int flags) {  

PackageParser packageParser =new PackageParser(archiveFilePath);  

DisplayMetrics metrics =new DisplayMetrics();  

metrics.setToDefaults();  

final File sourceFile =new File(archiveFilePath);  

PackageParser.Package pkg = packageParser.parsePackage(sourceFile, archiveFilePath, metrics, 0);  

if (pkg == null) {  

return null;  

    }  

packageParser.collectCertificates(pkg, 0);  

return PackageParser.generatePackageInfo(pkg, null, flags, 0, 0);  

}  

    在那之中参数archiveFilePath钦点APK文件路线;flags需安装PackageManager.GET_SIGNATURES位,以确定保证再次来到证书具名消息。

    具体怎么通过PackageParser获取签字音信在那边不做详述,具体代码请参谋PackageParser中的public boolean collectCertificates(Package pkg, int flags)和private Certificate[] loadCertificates(JarFile jarFile, JarEntry je, byte[] readBuffer)方法。至于什么在Android应用开荒中央银行使遮蔽的类及方法,能够参见作者的那篇文章:《Android应用开采中怎么样利用掩饰API》。

    紧接着,大家就能够通过packageInfo.signatures来访谈到APK的签字音信。还索要表明的是 Android中Signature和Java中Certificate的照料关系。它们的关联如上边代码所示:

[objc] view plain copy

pkg.mSignatures = new Signature[certs.length];  

for (int i=0; i

pkg.mSignatures[i] = new Signature(  

certs[i].getEncoded());  

}  

    也正是说signature = new Signature(certificate.getEncoded()); certificate证书中包涵了公钥和证书的别样中央新闻。公钥区别,证书确定互不相同样。大家能够通过certificate的getPublicKey方法获得公钥消息。所以比对具名证书本质上正是比对公钥消息。

    OK,获取到APK具名证书之后,就剩下比对了。那一个轻松,成效函数如下所示:

[objc] view plain copy

private boolean IsSignaturesSame(Signature[] s1, Signature[] s2) {  

if (s1 == null) {  

return false;  

    }  

if (s2 == null) {  

return false;  

    }  

HashSet set1 = new HashSet();  

for (Signature sig : s1) {  

set1.add(sig);  

    }  

HashSet set2 = new HashSet();  

for (Signature sig : s2) {  

set2.add(sig);  

    }  

// Make sure s2 contains all signatures in s1.  

if (set1.equals(set2)) {  

return true;  

    }  

return false;  

}  

APK签字比对的行使场景

    经过以上的论述,想必大家早已驾驭具名比对的规律和本人的完成格局了。那么如哪一天候怎么动静适合采用签字相比来保持Android APK的软件安全呢?

    个人觉得重视有以下二种情形:

1、 程序自检查评定。在程序运营时,自己举行签名比对。比对样本能够贮存在APK包内,也可贮存于云端。劣势是程序被破解时,自检查实验作用雷同恐怕遇到损坏,使其失效。

2、 可信赖任的第三方检查测试。由可靠的第三方前后相继肩负APK的软件安全主题素材。相比较样本由第三方搜罗,放在云端。这种方法适用于杀毒安全软件只怕APP马克et之类的软件下载市镇。瑕疵是亟需联网检验,在无网络状态下不恐怕完结效益。(不容许把大气的签字数据放在移动设备当地)。

3、 系统限定安装。那就涉及到改Android系统了。限定仅能安装有些证书的APK。软件公布商需求向系统发表上申请证书。假诺发掘标题,能追踪到是哪位软件揭橥商的职分。适用于系统提供商也许终端产品生产商。瑕玷是矫枉过正密封,不低价系统的开放性。

上述二种现象,即使各有隐疾,但劣点并不是无法克服的。举个例子,我们能够考虑程序自检查实验的效劳用native method的办法达成等等。软件安全部是叁个头眼昏花的课题,往往要求多样工夫协同利用,本领更加好的维持软件不被恶心破坏。

本文由pc28.am发布于计算机编程,转载请注明出处:应用签名,APK签名对比及说明

上一篇:据说是全球第一场微信小程序黑客马拉松,你想 下一篇:没有了
猜你喜欢
热门排行
精彩图文
  • 普通人如何从零开始写手帐,我的手账进化史
    普通人如何从零开始写手帐,我的手账进化史
    骨子里和诸两人同一,作者对于众多政工都轻易不平日四起,却很难坚持不渝。以致本身有一点点纳闷什么事物能让自家分外“专情”、“至死不渝”呢!
  • 微信公开学张小龙年度演说,小程序的运转格局
    微信公开学张小龙年度演说,小程序的运转格局
    小程序发布已过去3天,这个微信放的大招让整个互联网圈高潮了一把。目前业界已有各种小程序的分析和预测,也有很多诸如小程序解放了内存、小程序没
  • 行远自迩
    行远自迩
    Block是对象。 首先有个别:Block基础知识介绍 其次片段:Block平常使用的两种情形(方法回调,Cell点击事件,VC之间逆向传值) 运用block已经有一段时间了
  • 座谈23种设计格局在Android源码及项目中的应用,
    座谈23种设计格局在Android源码及项目中的应用,
    装饰者模式以对客户透明的方式动态地给一个对象附加上更多的责任,例如生活中常用的生日蛋糕,可以添加蓝莓,巧克力来装饰,可以动态地给一个对象
  • iOS开拓中落到实处展现gif图片教程
    iOS开拓中落到实处展现gif图片教程
    Android 的webView有回退栈,其实iOS的webView也有回退栈! webView的回退栈其实就是表示webView的层级! 目录 1.给navigation Bar 设置 title 颜色2.如何把一个CGPoint存入