Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android平台實現SSL單雙向驗證

Android平台實現SSL單雙向驗證

編輯:關於Android編程

環境:服務器: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工具,沒有自己弄個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. /** Called when the activity is first created. */
  20. @Override
  21. public void onCreate(Bundle savedInstanceState) {
  22. super.onCreate(savedInstanceState);
  23. setContentView(R.layout.main);
  24. tv = (TextView) findViewById(R.id.TextView01);
  25. et = (EditText) findViewById(R.id.EditText01);
  26. btn = (Button) findViewById(R.id.Button01);
  27. btn2 = (Button) findViewById(R.id.Button02);
  28. btn3 = (Button) findViewById(R.id.Button03);
  29. btn.setOnClickListener(new Button.OnClickListener(){
  30. @Override
  31. public void onClick(View arg0) {
  32. if(null != Client_sslSocket){
  33. getOut(Client_sslSocket, et.getText().toString());
  34. getIn(Client_sslSocket);
  35. et.setText("");
  36. }
  37. }
  38. });
  39. btn2.setOnClickListener(new Button.OnClickListener(){
  40. @Override
  41. public void onClick(View arg0) {
  42. try {
  43. Client_sslSocket.close();
  44. Client_sslSocket = null;
  45. } catch (IOException e) {
  46. e.printStackTrace();
  47. }
  48. }
  49. });
  50. btn3.setOnClickListener(new View.OnClickListener(){
  51. @Override
  52. public void onClick(View arg0) {
  53. init();
  54. getIn(Client_sslSocket);
  55. }
  56. });
  57. }
  58. public void init() {
  59. try {
  60. //取得SSL的SSLContext實例
  61. SSLContext sslContext = SSLContext.getInstance(CLIENT_AGREEMENT);
  62. //取得KeyManagerFactory和TrustManagerFactory的X509密鑰管理器實例
  63. KeyManagerFactory keyManager = KeyManagerFactory.getInstance(CLIENT_KEY_MANAGER);
  64. TrustManagerFactory trustManager = TrustManagerFactory.getInstance(CLIENT_TRUST_MANAGER);
  65. //取得BKS密庫實例
  66. KeyStore kks= KeyStore.getInstance(CLIENT_KEY_KEYSTORE);
  67. KeyStore tks = KeyStore.getInstance(CLIENT_TRUST_KEYSTORE);
  68. //加客戶端載證書和私鑰,通過讀取資源文件的方式讀取密鑰和信任證書
  69. kks.load(getBaseContext()
  70. .getResources()
  71. .openRawResource(R.drawable.kclient),CLIENT_KET_PASSWORD.toCharArray());
  72. tks.load(getBaseContext()
  73. .getResources()
  74. .openRawResource(R.drawable.lt_client),CLIENT_TRUST_PASSWORD.toCharArray());
  75. //初始化密鑰管理器
  76. keyManager.init(kks,CLIENT_KET_PASSWORD.toCharArray());
  77. trustManager.init(tks);
  78. //初始化SSLContext
  79. sslContext.init(keyManager.getKeyManagers(),trustManager.getTrustManagers(),null);
  80. //生成SSLSocket
  81. Client_sslSocket = (SSLSocket) sslContext.getSocketFactory().createSocket(SERVER_IP,SERVER_PORT);
  82. } catch (Exception e) {
  83. tag.e("MySSLSocket",e.getMessage());
  84. }
  85. }
  86. public void getOut(SSLSocket socket,String message){
  87. PrintWriter out;
  88. try {
  89. out = new PrintWriter(
  90. new BufferedWriter(
  91. new OutputStreamWriter(
  92. socket.getOutputStream()
  93. )
  94. ),true);
  95. out.println(message);
  96. } catch (IOException e) {
  97. e.printStackTrace();
  98. }
  99. }
  100. public void getIn(SSLSocket socket){
  101. BufferedReader in = null;
  102. String str = null;
  103. try {
  104. in = new BufferedReader(
  105. new InputStreamReader(
  106. socket.getInputStream()));
  107. str = new String(in.readLine().getBytes(),ENCONDING);
  108. } catch (UnsupportedEncodingException e) {
  109. e.printStackTrace();
  110. } catch (IOException e) {
  111. e.printStackTrace();
  112. }
  113. new AlertDialog
  114. .Builder(MySSLSocket.this)
  115. .setTitle("服務器消息")
  116. .setNegativeButton("確定", null)
  117. .setIcon(android.R.drawable.ic_menu_agenda)
  118. .setMessage(str)
  119. .show();
  120. }
  121. }


    單向:

    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


      調試中遇到的問題,提一下:

      一般在模擬器中能通過,在真實平台上就沒問題了。

      這裡需要注意的是證書的有效期,一定要在證書的有效期內操作

      雙向:

      雙向在單向的基礎上實現,不過要先生成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());
  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved