Keytool工具的使用。 在用Android平台上使用SSL,第一步就是生成证书。 1、证书的生成 1.1生成服务器端的证书py keytool -genkey -alias test -keystore test.jks 1.2 将keystore中的cert导出来,用来生成客户端的验证证书 [html] keytool -exportcert -alias test -file test.cert -keystore test.jks 1.3 生成Android平台的证书 因为Android 要求要BC证书,而Java的keytool本身不提供BKS格式,因此要自己手动配置。个人在配置的过程到了文件正在使用中,保存失败的情况,我的做法是将文件备份一下,用unlocker删除后将修改好备份放到原位置就好了。 1.3.1 下载 bcprov-ext-jdk15on-146.jar 到官网下载本地jdk对应的jar,复制到C:\Program Files\Java\jdk1.6.0_43\jre\lib\ext 1.3.2 配置bcprov 在 jdk_home\jre\lib\security\目录中找到 java.security 在内容增加一行(数字可以自己定义) [html] security.provider.11=org.bouncycastle.jce.provider.BouncyCastleProvider 1.3.3 生成android平台的证书 [html] keytool -importcert -keystore test.bks -file test.cert -storetype BKS -provider org.bouncycastle.jce.provider.BouncyCastleProvider 一、什么是SSL? SSL(Secure Sockets Layer 安全套接层),及其继任者传输层安全(Transport Layer Security,TLS)是为网络通信提供安全及数据完整性的一种安全协议。TLS与SSL在传输层对网络连接进行加密。 SSL/TLS协议位于HTTP协议与传输层协议之间,采用公钥技术,为两个应用间的通讯提供加密、完整性校验以及身份认证。 SSL协议提供了三个功能: 使用公钥证书对双端进行认证(一般仅进行服务器认证,客户端认证为可选) 通信加密(Condentiality) 数据完整性检查(Data integrity) 二、SSL握手 SSL会话以称之为SSL握手的一系列消息交换开始,在握手过程中服务器通过公钥技术向客户端认证自身(可选,客户端向服务器认证自身),客户端和服务器协商加密消息的对称密钥,SSL会话握手后的消息都使用对称密钥加密后传输,对称密钥还用于消息完整性检查。 Client->Server ClientHello Client向Server发送一个“ClientHello”消息,说明它支持的密码算法列表、压缩方法及最高协议版本,以及稍后将被使用的随机数 Version: 客户端支持TLS协议最高版本号(最高3.3) RandomNumber:客户端产生的28byte随机数,后续用作加密种子。 CipherSuites 客户端支持的加密算法和密钥大小列表 CompressionMethods 客户可支持的压缩算法 Server->Client ServerHello 服务器向客户端发送“ServerHello”消息,包含服务器选择的密码算法、压缩方法、协议版本以及服务器产生的随机数。 Version: 选择的TLS版本号 RandomeNumber:服务器产生的28字节随机数,后续用作加密种子 CipherSuite: 选择的加密算法和密钥大小。 CompressionMethod: 选择的数据压缩算法 Server->Client Certificate Server向Client发送自身的证书链,证书链从服务器的公钥证书(public-key certicate)开始一直到CA的根证书(certicate authority’s root certicate). 客户端需要对server的证书链进行验证,如果验证不通过,则终止连接。若验证通过,则可从server的公钥证书中获取到server的公钥。验证流程见后续介绍。 Server->Client CertificateRequest 如果Server需要认证Client,则发送此消息请求Client的公钥证书,此消息为可选。消息中包含 Certificate Types: Server可接收的证书类型列表 DistinguishedNames: Server可接收的CA DN列表。 Server->Client ServerHelloDone Server发送此消息通知Client已完成了初始化协商消息。 Client->Server Certificate 如果Server请求了Client的证书,即存在消息4,则client将自身的证书链信息发送给Server。Server要对Client的证书链进行验证,如果验证不通过,则终止连接,如果验证通过则可从Client的公钥证书中获取到Client的公钥。验证流程见后续介绍. Client->Server ClientKeyExchange Client向Server发送premaster secret,并且用Server的公钥加密。premaster secret用于双方计算出对后续消息加密的对称密钥. 使用Server的公钥加密的目的是确认Server具有消息3中所生成公钥证书的私钥,避免发送给伪造的服务器。 Client->Server CertificateVerify 如果Server请求了Client的证书,则还需要发送CertificateVerify消息,Client将到现在为止发送和接收到的握手消息,使用Client的私钥进行签名发送给Server,用于向Server证明其有消息6中声称Client公钥的私钥数据。Server可使用消息6中获得的Client公钥对消息进行验证。 Client->Server ChangeCipherSpec Client使用客户端随机数,服务器随机数以及premaster secret产生加密消息的对称密钥Master Secret。然后发送此消息告知Server后续消息将使用对称密钥加密 Client->Server Finished Client向Server发送此消息通知对端协商成功,此消息使用协商的公钥密钥加密。 Server->Client ChangeCipherSpec Server使用客户端随机数,服务器随机数以及premaster secret产生加密消息的对称密钥Master Secret。然后发送此消息告知Client后续消息将使用对称密钥加密. Server->Client Finished Server向Client发送此消息通知对端协商成功,此消息使用协商的公钥密钥加密。 三、SSL通信模式: 1.服务端: SSL服务端需要通过SSL服务套接字来提供服务接口,而SSL服务套接字需要通过SSL上下文实例来创建。以下是对SSL服务端的启用过程的描述。 (1)通过指定协议(一般是TLS)获取SSL上下文(SSLContext)实例。 (2)通过指定算法(X.509相关)获取密钥管理器工厂(KeyManagerFactory)实例。 (3)通过指定类型和提供者获取密钥库(KeyStore)实例。 (4)密钥库实例使用约定的密码加载(Load)密钥库文件(.keystore)。 (5)密钥管理器工厂实例使用约定的密码和(4)中密钥库进行初始化(Initialize)。 (6)SSL上下文实例通过密钥管理器工厂实例提供的密钥管理器来初始化(Initialize)。 (7)当SSL上下文实力初始化成功后,就可以获取该上下文势力所关联的服务套接字工厂(ServerSocketFactory)实例 (8)服务套接字工厂实例依据指定的服务端口来创建(Create)服务套接字(ServerSocket)。 (9)当SSL服务套接字创建成功,就可以等待客户端的连接,与客户端进行通信。 (10)通信完毕可以关闭服务套接字。 2.客户端 (1)通过指定协议(一般是TLS)获取SSL上下文(SSLContext)实例。 (2)通过指定算法(X.509相关)获取密钥管理器工厂(KeyManagerFactory)实例。 (3)通过指定算法(X.509相关)获取信任管理器工厂(TrustManagerFactory)实例。 (4)通过指定类型和提供者获取密钥库(KeyStore)实例。 (5)通过指定类型和提供者获取信任密钥库(KeyStore)实例。 (6)(4)中密钥库实例使用约定的密码加载(Load)密钥库文件(.keystore)。 (7)(5)中信任密钥库实例使用约定的密码加载(Load)密钥库文件(.keystore)。 (8)密钥管理器工厂实例使用约定的密码和(4)中密钥库进行初始化(Initialize)。 (9)信任密钥管理器工厂实例使用约定的密码和(5)中密钥库进行初始化(Initialize)。 (10)当SSL上下文实力初始化成功后,就可以获取该上下文实例所关联的套接字工厂(SocketFactory)实例 (11)套接字工厂实例依据指定的主机和端口来创建(Create)客户端套接字(Socket)。 (12)当SSL服务套接字创建成功,就可以向服务端发送请求,与服务端进行通信。 (13)通信完毕可以关闭服务套接字。 服务端代码: [java] import java.io.BufferedInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.net.ServerSocket; import java.net.Socket; import java.net.SocketAddress; import java.security.KeyManagementException; import java.security.KeyStore; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import java.security.UnrecoverableKeyException; import java.security.cert.CertificateException; import javax.net.ServerSocketFactory; import javax.net.ssl.KeyManager; import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.SSLContext; /** * @author draem0507@gmail.com * @TODO java线程开发之四 SSL加密 * 开发步骤 * 1.生成服务端密钥 * 2.导出服务端证书 * 3.生成客户端密钥 * 4. 程序开发测试 * 关于证书的生成请参考readme.txt * 参考资料:http://chrui.iteye.com/blog/1018778 * @version 1.0 * @date 2013-5-7 23:22:45 * @update 2013-5-8 10:22:45 * @blgos http://www.cnblogs.com/draem0507 */ public class Server { private ServerSocket serverSocket; private final static char[] password="1qaz2wsx".toCharArray(); private SSLContext context; private InputStream inputStream; public Server() { inputStream=this.getClass().getResourceAsStream("/test.jks"); initContext(); try { //直接运行会报 javax.net.ssl.SSLException: //ServerSocketFactory factory= SSLServerSocketFactory.getDefault(); ServerSocketFactory factory= context.getServerSocketFactory(); // serverSocket = new ServerSocket(10000); serverSocket=factory.createServerSocket(10000); System.out.println("======启动安全SocektServer成功========="); while (true) { Socket socket = serverSocket.accept(); new ReceiveSocket(socket).start(); } } catch (IOException e) { e.printStackTrace(); } } //ssl 上下文对象的初始化 private void initContext() { try { KeyStore store=KeyStore.getInstance("JKS"); store.load(inputStream, password); KeyManagerFactory factory=KeyManagerFactory.getInstance("SunX509"); factory.init(store,password); KeyManager []keyManagers=factory.getKeyManagers(); context=SSLContext.getInstance("SSL"); context.init(keyManagers, null , null); } catch (KeyStoreException e) { e.printStackTrace(); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } catch (CertificateException e) { e.printStackTrace(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (UnrecoverableKeyException e) { e.printStackTrace(); } catch (KeyManagementException e) { e.printStackTrace(); } } public static void main(String[] args) { new Server(); } private class ReceiveSocket extends Thread { private Socket socket; public ReceiveSocket(Socket socket) { this.socket = socket; } private ObjectInputStream reader; private ObjectOutputStream writer; @Override public void run() { try { reader=new ObjectInputStream(new BufferedInputStream(socket.getInputStream())); //writer=new ObjectOutputStream(socket.getOutputStream()); // 开启无限循环 监控消息 //java.io.EOFException Object obj= reader.readUTF(); SocketAddress address = socket.getRemoteSocketAddress(); System.out.println(address.toString() + ">\t" + obj); // Object obj= reader.readObject(); // if(obj!=null) // { // User user =(User)obj; // System.out.println("id=="+user.getPassword()+"\tname=="+user.getName()); // } // while (true) {} } catch (IOException e) { e.printStackTrace(); } finally { if (null != reader) { try { reader.close(); } catch (IOException e) { e.printStackTrace(); } } if (null != writer) { try { reader.close(); } catch (IOException e) { e.printStackTrace(); } } try { socket.close(); } catch (IOException e) { e.printStackTrace(); } } } } } Android客户端代码: [java] protected Void doInBackground(Void... params) { Log.i(TAG, "doInBackground"); try { SSLContext context; KeyStore ts = KeyStore.getInstance("BKS"); ts.load(getResources().openRawResource(R.raw.test), "1qaz2wsx".toCharArray()); TrustManagerFactory tmf = TrustManagerFactory .getInstance("X509"); tmf.init(ts); TrustManager[] tm = tmf.getTrustManagers(); context = SSLContext.getInstance("SSL"); context.init(null, tm, null); SocketFactory factory = context.getSocketFactory(); SSLSocket socket = (SSLSocket) factory.createSocket( "192.168.70.249", 10000); ObjectOutputStream out = new ObjectOutputStream( socket.getOutputStream()); out.writeUTF(UUID.randomUUID().toString()); out.flush(); System.out.println("========客户端发送成功========="); ; socket.close(); } catch (Exception ex) { ex.printStackTrace(); } return null; } 四、HTTPS HTTPS可以视为HTTP的安全版本(Secure),其安全基础基于SSL协议(Secure Socket Layer,安全套接字层)。HTTPS在HTTP的基础上添加了一个 加密和身份验证。其默认端口是443.对于一些对数据安全要求比较高的网络应用,比如网络支付,网上银行,都是采用HTTPS通信机制,其规范:RFC2818 HTTPS URL连接的方式访问HTTPS服务器与HTTP URL访问HTTP服务器的方式基本相同。用到的类:HttpsURLConnection。 代码例子(验证服务器): HttpsURLConnection方式 [java] public static String getHttpsContent(Map<String, String> paramsMap, String urlPath){ try{ File bksFile = new File("bks文件路径"); if(bksFile.exists()){ InputStream keyStoreInput = new FileInputStream(bksFile); String keyStoreType = KeyStore.getDefaultType(); KeyStore keyStore = KeyStore.getInstance(keyStoreType); keyStore.load(keyStoreInput, KEYSTORE_PASSWORD.toCharArray()); // Create a TrustManager that trusts the CAs in our KeyStore String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm(); TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm); tmf.init(keyStore); KeyManagerFactory kmf = KeyManagerFactory.getInstance("X509"); kmf.init(keyStore, KEYSTORE_PASSWORD.toCharArray()); // Create an SSLContext that uses our TrustManager SSLContext sslContext = SSLContext.getInstance("TLS"); sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); X509HostnameVerifier hostnameVerifier = SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER; HttpsURLConnection.setDefaultHostnameVerifier(hostnameVerifier); StringBuilder entityBuilder = new StringBuilder(""); if(paramsMap!=null && !paramsMap.isEmpty()){ for(Map.Entry<String, String> entry : paramsMap.entrySet()){ entityBuilder.append(entry.getKey()).append('='); entityBuilder.append(URLEncoder.encode(entry.getValue(), HTTP.UTF_8)); entityBuilder.append('&'); } entityBuilder.deleteCharAt(entityBuilder.length() - 1); } byte[] entity = entityBuilder.toString().getBytes(); // Tell the URLConnection to use a SocketFactory from our SSLContext //URL url = new URL("https://172.16.18.109"); URL url = new URL(urlPath); HttpsURLConnection urlConnection = (HttpsURLConnection) url .openConnection(); urlConnection.setSSLSocketFactory(sslContext.getSocketFactory()); urlConnection.setConnectTimeout(5 * 1000); urlConnection.setRequestMethod("POST"); urlConnection.setDoOutput(true);//允许输出数据 urlConnection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); urlConnection.setRequestProperty("Content-Length", String.valueOf(entity.length)); OutputStream outStream = urlConnection.getOutputStream(); outStream.write(entity); outStream.flush(); outStream.close(); InputStream in = urlConnection.getInputStream(); StringBuffer sb = new StringBuffer(); String line = null; char ch = '\u0000'; int temp = 0 ; while ((temp = in.read()) != -1) { ch = (char) temp; sb.append((char) temp); } String result = sb.toString(); return result; } return "-1"; }catch(Exception e){ e.printStackTrace(); return "-2"; } } HttpClient方式: [java] public static synchronized HttpClient getHttpClient(Context context) throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException, KeyManagementException, UnrecoverableKeyException { if(null==httpClient) { AssetManager sm= context.getAssets(); InputStream keyStroreInputStream=sm.open("ca_zx.bks"); KeyStore keyStore=KeyStore.getInstance(KeyStore.getDefaultType()); keyStore.load(keyStroreInputStream, KEYSTORE_PASSWORD.toCharArray()); SSLSocketFactory sf=new MySSLSocketFactory(keyStore); sf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER); HttpParams params=new BasicHttpParams(); HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1); HttpProtocolParams.setContentCharset(params, HTTP.UTF_8); HttpProtocolParams.setUseExpectContinue(params, true); ConnManagerParams.setTimeout(params, 10000); HttpConnectionParams.setConnectionTimeout(params, 15000); HttpConnectionParams.setSoTimeout(params, 20000); SchemeRegistry schreg=new SchemeRegistry(); schreg.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80)); schreg.register(new Scheme("https", sf , 443)); ClientConnectionManager conman=new ThreadSafeClientConnManager(params, schreg); httpClient=new DefaultHttpClient(conman, params); } return httpClient; } private static class MySSLSocketFactory extends SSLSocketFactory { SSLContext sslContext=SSLContext.getInstance("TLS"); public MySSLSocketFactory(KeyStore truststore) throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException { super(truststore); TrustManager tm=new X509TrustManager() { @Override public X509Certificate[] getAcceptedIssuers() { return null; } @Override public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { } @Override public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { } }; KeyManagerFactory kmf = KeyManagerFactory.getInstance("X509"); kmf.init(truststore, KEYSTORE_PASSWORD.toCharArray()); sslContext.init(kmf.getKeyManagers(), new TrustManager[]{ tm}, null); } @Override public Socket createSocket() throws IOException { // TODO Auto-generated method stub return sslContext.getSocketFactory().createSocket(); } @Override public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException, UnknownHostException { return sslContext.getSocketFactory().createSocket(socket, host, port, autoClose); } }


更多相关文章

  1. 新浪微博请求数据出错(Android(安卓)Volley Https证书不信任)的解
  2. Android(安卓)4.2短信小记
  3. Android(安卓)MQTT使用详解
  4. Android中EditText的错误消息显示
  5. Android判断当前系统时间是否在指定时间的范围内(免消息打扰)
  6. Android(安卓)keystore的使用方法
  7. [置顶] android NFC开发实例
  8. Android与mqtt双向SSL认证
  9. Android(安卓)FaceBook登录接入--散列密钥获取

随机推荐

  1. Android(安卓)面试题(有详细答案)
  2. Android(安卓)集成融云
  3. Daager2-初认识一
  4. Android中Fragment的用法总结
  5. Android(安卓)手机厂商推送服务调研
  6. Android(安卓)应用程序分析之Calculator
  7. Android(安卓)微信分享,无需那么麻烦。
  8. Android(安卓)Studio ADB not responding
  9. Android开发之旅:环境搭建及HelloWorld (A
  10. 手把手教你仿一个知乎日报Android客户端(