文档章节

【转帖】android平台ssl单双向验证

mellen
 mellen
发布于 2015/06/25 14:12
字数 1875
阅读 3676
收藏 14
点赞 0
评论 0

    原文出自:http://blog.csdn.net/hfeng101/article/details/10163627http://blog.csdn.net/hfeng101/article/details/10163627

       android平台ssl单双向验证            

       分类:             JAVA             android开发              2013-08-21 23:51     4672人阅读     评论(16)     收藏     举报    

AndroidSSL

最近做android平台ssl通信研究,被坑了好些,最后历经磨难,终于搞定它了,得到的结论:实践才是检验坑有多深的最佳途径!!

看网上的中文资料,提到android ssl通信的也有,但都是零零碎碎,提到双向的实现更少,国外有些资料还可以,推荐stackoverflow,里面有不少探讨android ssl的好帖子,不过是英文的,这个(~~!)就不解释了!

话不多说,开始了。


环境:

服务器:apache服务器,openssl。

客户端:PC、java平台、android平台。

思路:

1、先搞定ssl单向验证,再解决双向。

2、先PC,再java平台,再android,不一定非得这样,自由选择,个人是为了弄清整个流程,多走了些路。

过程步骤:

1、在pc上用apache搭建了一个http服务器,用openssl建立自签名的CA证书ca.crt,签发服务器证书server.crt,签发客户端证书client.crt。(apache+openssl配置ssl通信网上资料很多)

2、安装ca.crt,配置服务器,开启单向验证,用浏览器测试验证单向ssl通信。

3、将client.crt和client.key打包生成pkcs12格式的client.pfx文件。

4、配置服务器,开启双向验证,通过浏览器导入client.pfx文件,测试验证双向ssl通信。


重点:

Java平台默认识别jks格式的证书文件,但是android平台只识别bks格式的证书文件,需要在java中配置BC库,个人推荐参考:http://hi.baidu.com/yaming/item/980f253e17f585be124b142d,配置好BC库,看看有没有keytool工具,没有自己弄个,这个网上资料多。


代码参考:http://momoch1314.iteye.com/blog/540613,由于服务端有apache,上面的代码就不用了,此处列出客户端,此文中是通过socket通信的,建议改成https通信,效果会更好,因为和apache服务器打交道,处理起来会更方便。(里面有些东西需要微调的,希望各位自己改一下,对于某些人来说,可能会有些坑,有疑问,请留言,本屌尽力解答)

  1. public class MySSLSocket extends Activity {  

  2.     private static final int SERVER_PORT = 50030;//端口号  

  3.     private static final String SERVER_IP = "218.206.176.146";//连接IP  

  4.     private static final String CLIENT_KET_PASSWORD = "123456";//私钥密码  

  5.     private static final String CLIENT_TRUST_PASSWORD = "123456";//信任证书密码  

  6.     private static final String CLIENT_AGREEMENT = "TLS";//使用协议  

  7.     private static final String CLIENT_KEY_MANAGER = "X509";//密钥管理器  

  8.     private static final String CLIENT_TRUST_MANAGER = "X509";//  

  9.     private static final String CLIENT_KEY_KEYSTORE = "BKS";//密库,这里用的是BouncyCastle密库  

  10.     private static final String CLIENT_TRUST_KEYSTORE = "BKS";//  

  11.     private static final String ENCONDING = "utf-8";//字符集  

  12.     private SSLSocket Client_sslSocket;  

  13.     private Log tag;  

  14.     private TextView tv;  

  15.     private Button btn;  

  16.     private Button btn2;  

  17.     private Button btn3;  

  18.     private EditText et;  

  19.       

  20.     /** Called when the activity is first created. */  

  21.     @Override  

  22.     public void onCreate(Bundle savedInstanceState) {  

  23.         super.onCreate(savedInstanceState);  

  24.         setContentView(R.layout.main);  

  25.         tv = (TextView) findViewById(R.id.TextView01);  

  26.         et = (EditText) findViewById(R.id.EditText01);  

  27.         btn = (Button) findViewById(R.id.Button01);  

  28.         btn2 = (Button) findViewById(R.id.Button02);  

  29.         btn3 = (Button) findViewById(R.id.Button03);  

  30.           

  31.         btn.setOnClickListener(new Button.OnClickListener(){  

  32.             @Override  

  33.             public void onClick(View arg0) {  

  34.                 if(null != Client_sslSocket){  

  35.                     getOut(Client_sslSocket, et.getText().toString());  

  36.                     getIn(Client_sslSocket);  

  37.                     et.setText("");  

  38.                 }  

  39.             }  

  40.         });  

  41.         btn2.setOnClickListener(new Button.OnClickListener(){  

  42.             @Override  

  43.             public void onClick(View arg0) {  

  44.                 try {  

  45.                     Client_sslSocket.close();  

  46.                     Client_sslSocket = null;  

  47.                 } catch (IOException e) {  

  48.                     e.printStackTrace();  

  49.                 }  

  50.             }  

  51.         });  

  52.         btn3.setOnClickListener(new View.OnClickListener(){  

  53.             @Override  

  54.             public void onClick(View arg0) {  

  55.                 init();  

  56.                 getIn(Client_sslSocket);  

  57.             }  

  58.         });  

  59.     }  

  60.       

  61.     public void init() {  

  62.         try {  

  63.             //取得SSL的SSLContext实例  

  64.             SSLContext sslContext = SSLContext.getInstance(CLIENT_AGREEMENT);  

  65.             //取得KeyManagerFactory和TrustManagerFactory的X509密钥管理器实例  

  66.             KeyManagerFactory keyManager = KeyManagerFactory.getInstance(CLIENT_KEY_MANAGER);  

  67.             TrustManagerFactory trustManager = TrustManagerFactory.getInstance(CLIENT_TRUST_MANAGER);  

  68.             //取得BKS密库实例  

  69.             KeyStore kks= KeyStore.getInstance(CLIENT_KEY_KEYSTORE);  

  70.             KeyStore tks = KeyStore.getInstance(CLIENT_TRUST_KEYSTORE);  

  71.             //加客户端载证书和私钥,通过读取资源文件的方式读取密钥和信任证书  

  72.             kks.load(getBaseContext()  

  73.                     .getResources()  

  74.                     .openRawResource(R.drawable.kclient),CLIENT_KET_PASSWORD.toCharArray());  

  75.             tks.load(getBaseContext()  

  76.                     .getResources()  

  77.                     .openRawResource(R.drawable.lt_client),CLIENT_TRUST_PASSWORD.toCharArray());  

  78.             //初始化密钥管理器  

  79.             keyManager.init(kks,CLIENT_KET_PASSWORD.toCharArray());  

  80.             trustManager.init(tks);  

  81.             //初始化SSLContext  

  82.             sslContext.init(keyManager.getKeyManagers(),trustManager.getTrustManagers(),null);  

  83.             //生成SSLSocket  

  84.             Client_sslSocket = (SSLSocket) sslContext.getSocketFactory().createSocket(SERVER_IP,SERVER_PORT);  

  85.         } catch (Exception e) {  

  86.             tag.e("MySSLSocket",e.getMessage());  

  87.         }  

  88.     }  

  89.           

  90.     public void getOut(SSLSocket socket,String message){  

  91.         PrintWriter out;  

  92.         try {  

  93.             out = new PrintWriter(  

  94.                     new BufferedWriter(  

  95.                             new OutputStreamWriter(  

  96.                                     socket.getOutputStream()  

  97.                                     )  

  98.                             ),true);  

  99.             out.println(message);  

  100.         } catch (IOException e) {  

  101.             e.printStackTrace();  

  102.         }  

  103.     }  

  104.       

  105.     public void getIn(SSLSocket socket){  

  106.         BufferedReader in = null;  

  107.         String str = null;  

  108.         try {  

  109.             in = new BufferedReader(  

  110.                     new InputStreamReader(  

  111.                             socket.getInputStream()));  

  112.             str = new String(in.readLine().getBytes(),ENCONDING);  

  113.         } catch (UnsupportedEncodingException e) {  

  114.             e.printStackTrace();  

  115.         } catch (IOException e) {  

  116.             e.printStackTrace();  

  117.         }  

  118.         new AlertDialog  

  119.         .Builder(MySSLSocket.this)  

  120.         .setTitle("服务器消息")  

  121.         .setNegativeButton("确定"null)  

  122.         .setIcon(android.R.drawable.ic_menu_agenda)  

  123.         .setMessage(str)  

  124.         .show();  

  125.     }  

  126. }  



单向:

1、用keytool将ca.crt导入到bks格式的证书库ca.bks,用于验证服务器的证书,命令如下:

keytool -import -alias ca -file ca.crt -keystore ca.bks -storetype BKS -provider org.bouncycastle.jce.provider.BouncyCastleProvider

2、服务器配置成单向验证,将ca.bks放到android工程的assets或raw下,对应的读取就是代码中的

  1. kks.load(getBaseContext()  

  2.                     .getResources()  

  3.                     .openRawResource(R.drawable.kclient),CLIENT_KET_PASSWORD.toCharArray()); 

不一定是R.drawable.kclient,自己根据实际做修改,读取文件,不懂网上查,不啰嗦了。

至此,单向ssl通信应该是OK了。

(PS: 针对2中的操作不一定非得这么做,也可以把ca.bks导入到android平台下的cacerts.bks文件中,然后从这个文件读取认证,怎么导入,网上资料很多,如:http://blog.csdn.net/haijun286972766/article/details/6247675


调试中遇到的问题,提一下:

一般在模拟器中能通过,在真实平台上就没问题了。

个人遇到一个最蛋疼的问题是模拟器上通过了,但真实平台就是报错,卡了好几天,查了好多资料没查到,网上也有类似的提问,但没有靠谱的解答,最后硬着头皮终于查出来是真实平台的时间不对,2007年,不在证书的有效期内,就一个感受:坑!!


++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

双向:

双向在单向的基础上实现,不过要先生成android平台能识别的客户端证书,这个玩意也伤脑筋,网上提到生成bks格式客户端证书的资料很少,鲜有借鉴之用。

在这个点上,太伤脑筋了,估计很多伙计也在这儿卡得蛋疼,一开始是毫无头绪,在PC、JAVA平台上生成客户端证书,都能测通,但是转到android平台就傻眼了,用keytool将其它工具生成的crt证书,导成bks格式,不通;用keytool工具新生成bks格式证书,也不通;

各种能想的方法试尽,一度怀疑自己是不是哪个细节出错了,理论上肯定能做的东西,怎么看不到一点可实现性,找资料连续几天,一点进展都没。

后面看国外的资料上提到先用openssl生成pkcs12的.pfx格式证书,然后用工具portecle转换成BKS格式,在android平台上使用,一开始是直接强制性转换,出错,怎么转都转不成功,但是转换成jks格式又没问题,只能根据提示错误,找解决方案,试了好多还是不行,又迷茫了;

1、最后看到国外的资料上的一句话,顿悟灵光,用portecle工具,先建立一个bks格式的keystore,然后将client.pfx中的key pair导入(import key pair),再保存bks文件,测试成功,事实证明:二了一点。

PS:用portecle直接转应该是可以的,只是我一直没转成功过,可能是我的java环境有问题,老提示illegal key size。

2、将服务器配置成双向验证,将ca.bks放到android工程的assets或raw下,对应的读取就是代码中的

  1. tks.load(getBaseContext()  

  2.                     .getResources()  

  3.                     .openRawResource(R.drawable.lt_client),CLIENT_TRUST_PASSWORD.toCharArray());

至此,问题基本搞定,不过个人还有个心瘤,理论上用keytool生成bks格式的证书再使用,但是个人各种方法试尽,仍旧没有结果,网上也没找到资料,原谅我的无能,如果有能实现的,麻烦分享一下,感激不尽!!!


太晚了,洗洗睡鸟,写得有点糙,如有疑问:留言解答!!





http://momoch1314.iteye.com/blog/540613

本文转载自:http://blog.csdn.net/hfeng101/article/details/10163627

共有 人打赏支持
mellen
粉丝 9
博文 114
码字总数 69070
作品 1
南京
部门经理
Webview SslError处理总结

如何处理应用中的 WebView SSL 错误处理程序提醒 本文面向的是在应用中采用的 WebViewClient.onReceivedSslError 处理程序实施方式不安全的开发者。具体来说,这种实施方式会忽略所有 SSL 证...

IamOkay
2017/06/20
0
0
https HttpsURLConnection请求的单向认证

参考链接 android httpClient(https/http)的优化构建方式一 android httpClient(https/http)的优化构建方式二 Java https请求 HttpsURLConnection php使用curl库进行ssl双向认证 OpenSSL生成...

IamOkay
2015/09/03
5.1K
0
android httpClient(https/http)的优化构建方式一

参考:基于java的https双向认证,android上亦可用 Android Https相关完全解析 当OkHttp遇到Https 在android中,经常不可避免的的使用https和http访问网络数据,因此需要先构建一个网络访问cli...

IamOkay
2014/10/31
0
0
基于Android平台的Web服务技术研究

基于Android平台的Web服务技术研究 Android 平台是Google 于2007 年11 月推出的一种智能手机平台,由操作系统、中间件、用户界面、应用软件组成,全面整合的移动"软件栈".诚然,提到Android...

李禾根
2012/10/09
0
2
github for window 中 git shell 设置代理方法和解决ssl证书错误的问题

因为国内特殊的网络环境,所以用github for windows,在使用git shell的clone命令是会出现这样的情况 git clone https://code.google.com/p/android-os-monitor.osmonitor/ Cloning into and...

subying
2014/01/17
0
2
基于Android平台简易即时通讯的研究与设计

1 Android平台简介 Android是Google公司于2007年11月5日推出的手机操作系统,经过2年多的发展,Android平台在智能移动领域占有不小的份额,由Google为首的40多家移动通信领域的领军企业组成开...

今幕明
2014/12/11
0
0
为Phonegap Android平台增加websocket支持,使默认成为socket.io首选通

为Phonegap Android平台增加websocket支持,使默认成为socket.io首选通道选择 广而告之 使用socket.io作为跨浏览器平台的实时推送首选,经测试在各个主流浏览器上测试都确实具有良好的下实时...

james_laughing
2014/12/17
0
2
Appium 1.8.0 发布,全面支持 W3C WebDriver 规范

Appium 是一个开源、跨平台的自动化测试工具,最初主要用于测试原生和轻量移动应用,包括 iOS 和 Android ,目前还支持对 Windows 平台上的应用的自动化测试。 Appium 1.8.0 发布,引入了对 ...

王练
04/25
0
0
2014.7.28 自己给自己挖的坑

本来今天把网络层基本搞定了的。然后打算移植到android平台看下,之前想象应该是很简单的一个事情。但是由于之前自己给自己挖的坑。害我调了12个小时。 是这样的。 本来我当时使用cocos new...

WPracker
2014/07/29
0
0
Android 渗透测试学习手册 第三章 Android 应用的逆向和审计

第三章 Android 应用的逆向和审计 作者:Aditya Gupta 译者:飞龙 协议:CC BY-NC-SA 4.0 在本章中,我们将查看 Android 应用程序或文件,并了解其不同的组件。 我们还将使用工具(如 Apktoo...

apachecn_飞龙
2016/12/11
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

Webpack使用nodemon实时打包编译

业务场景: 1.编写一个npm组件包并且link到了项目文件中 2.需要不断的修改并run build编译npm包并且在项目run dev 查看效果 3.问题: 每次改完npm包都要手动run build编译十分的麻烦且低效,可不...

JamesView
16分钟前
0
0
电脑炸了,浪费我好几天时间,还是简要记下来吧

我的小本本一直在兢兢业业的干活,然而前几天说炸就炸了...... 爆炸现场: 软件: windows10 pro + EIS11+ 360卫士 BIOS:N1DET98W 2.24 硬件: Xeon E3 1505-V5 nv-M3000M thinkpadP70:20E...

Oh_really
20分钟前
0
0
Git之branch和checkout

1.branch是查看、创建、删除分支 #>git branch --helpNAME git-branch - List, create, or delete branchesSYNOPSIS git branch [--color[=<when>] | --no-color] [......

汉斯-冯-拉特
22分钟前
0
0
Mybatis拦截器之数据权限过滤与分页集成

需求场景 最近项目有个数据权限的业务需求,要求大致为每个单位只能查看本级单位及下属单位的数据,例如:一个集团军下属十二个旅,那么军级用户可以看到所有数据,而每个旅则只能看到本旅部...

佛系程序猿灬
31分钟前
8
0
SpringCloud 微服务 (十六) 服务追踪 Zipkin

问题 在服务中,有一个接口,该A接口中又调用了其他服务的B、C、D接口,出现一个请求耗时大的问题,这时候并不知道该B、C、D接口中哪个接口造成的耗时量,然后比如确定C服务接口出现的耗时量大,但...

___大侠
今天
0
0
Java面试基础篇——第八篇:抽象类与接口的区别

1.抽象类 抽象类:如果一个类中包含有抽象方法,或这个类使用abstract关键字修饰,则称这个类是抽象类。 抽象方法是什么呢?抽象方法就是指用abstract关键字修饰的方法。 需要注意的是:抽象...

developlee的潇洒人生
今天
2
0
jsoup 相关资料

1.jsoup 2.Jsoup概述 3.jsoup入门 4.jsoup Java HTML Parser 1.11.3 API

IT追寻者
今天
1
0
JPA @MappedSuperclass 注解说明

基于代码复用和模型分离的思想,在项目开发中使用JPA的@MappedSuperclass注解将实体类的多个属性分别封装到不同的非实体类中。 1.@MappedSuperclass注解只能标准在类上:@Target({java.lang....

海博1600
今天
0
0
【一】Scala Configuration 相关API

Play使用了 Typesafe config library,但是也提供了一个有着更多Scala高级特性的的 Configuration 封装。不熟悉Typesafe配置的开发者可以移步 configuration文件的语法和特性文档。 读取配置...

Landas
今天
3
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部