Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> android ssl驗證、https驗證

android ssl驗證、https驗證

編輯:關於Android編程

准備知識:   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協議提供了三個功能: 使用公鑰證書對雙端進行認證(一般僅進行服務器認證,客戶端認證為可選) 通信加密(Confidentiality) 數據完整性檢查(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 certificate)開始一直到CA的根證書(certificate authority’s root certificate). 客戶端需要對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  [email protected]   * @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. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved