http://sehyo88.tistory.com/23


http://sehyo88.tistory.com/entry/11-TLS-SSL-%EB%B3%B4%EC%95%88%EC%86%8C%EC%BC%93-%EA%B5%AC%ED%98%84-in-Android-1


http://stackoverflow.com/questions/4065379/how-to-create-a-bks-bouncycastle-format-java-keystore-that-contains-a-client-c


그냥 소켓통신을 해봤으니 '보안'이 들어간 소켓통신을 해보자.

(통신관련 공부를 해본적이 없어서 그냥 해본대로만 적어놓아야 겠다.)


Server구현

먼저, keytool을 이용해서 keystore랑 인증서를 만들어 보자.

참조 : http://blog.naver.com/PostView.nhn?blogId=w123654&logNo=10104271717

keytool을 사용한 keyStore 생성 

(c:/java/jdk1.7.0_25/bin/keytool 사용 - 물론 cmd창에서 해야한다.)



keytool을 사용한 keyStore 생성 (JDK)

 

keytool -genkey -alias server -keyalg RSA -keystore server.keystore (서버 Keystore, 인증서 생성)

keytool -export -alias server -keystore server.keystore -file broker.cert (서버인증서 추출)

keytool -genkey -alias client -keyalg RSA -keystore client.keystore (클라이언트 Keystore, 인증서 생성)

keytool -import -alias server -keystore client.truststore -file broker.cert (서버인증서 import)


cer, crt (인증서파일)
csr --> 인증서(public key)발급

 

keytool -genkey -alias server -keyalg RSA -keystore c:/k/server.keystore

(서버 Keystore, 인증서 생성)

keytool -export -alias server -keystore c:/k/server.keystore -file c:/k/server.cer

(서버인증서 추출)


일단  pc에서 java를 이용한 server를 만들어보자.


  1. import java.io.BufferedReader;  
  2. import java.io.BufferedWriter;  
  3. import java.io.IOException;  
  4. import java.io.InputStreamReader;  
  5. import java.io.OutputStreamWriter;  
  6. import java.io.PrintWriter;  
  7. import java.net.ServerSocket;  
  8. import java.net.Socket;  
  9.   
  10. import javax.net.ServerSocketFactory;  
  11. import javax.net.ssl.SSLServerSocketFactory;  
  12.    
  13. public class TCPServer implements Runnable {  
  14.    
  15.     public static final int ServerPort = 9999;  
  16.    
  17.     @Override  
  18.     public void run() {  
  19.           
  20.         System.setProperty("javax.net.ssl.keyStore""c:/k/server.keystore");   
  21.         System.setProperty("javax.net.ssl.keyStorePassword""changeit");  
  22.        try {  
  23.             //System.out.println("S: Connecting...");  
  24.             //serverSocket = new ServerSocket(ServerPort);  
  25.    
  26.             ServerSocketFactory serverSocketFactory = SSLServerSocketFactory.getDefault();  
  27.             ServerSocket serverSocket = null;  
  28.        
  29.             try {  
  30.                 serverSocket = serverSocketFactory.createServerSocket(ServerPort);  
  31.             } catch (IOException ignored) {  
  32.                 ignored.printStackTrace();  
  33.                 System.err.println("Unable to create server");  
  34.                 System.exit(-1);  
  35.             }  
  36.             System.out.println("SSL sever test");  
  37.               
  38.             while (true) {  
  39.                 Socket client = serverSocket.accept();  
  40.                 System.out.println("S: Receiving...");  
  41.                 try {  
  42.                     BufferedReader in = new BufferedReader(new InputStreamReader(client.getInputStream()));  
  43.                     String str = in.readLine();  
  44.                     System.out.println("S: Received: '" + str + "'");  
  45.                       
  46.                    // PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(client.getOutputStream())), true);  
  47.                     //out.println("Server Received " + str);  
  48.                 } catch (Exception e) {  
  49.                     System.out.println("S: Error");  
  50.                     e.printStackTrace();  
  51.                 } finally {  
  52.                     client.close();  
  53.                     System.out.println("S: Done.");  
  54.                 }  
  55.             }  
  56.         } catch (Exception e) {  
  57.             System.out.println("S: Error");  
  58.             e.printStackTrace();  
  59.         }  
  60.     }  
  61.    
  62.     public static void main(String[] args) {  
  63.    
  64.         Thread desktopServerThread = new Thread(new TCPServer());  
  65.         desktopServerThread.start();  
  66.    
  67.     }  
  68.    
  69. }  


위 프로그램을 실행 하면 아래 그림과 같이 나온다.

21575140526F46EE2A8975

Client구현

이제 안드로이드에서 Client를 구현하면 되는데, 
먼저 테스트 해보니까 같은 네트워크에서만 되는것 같다.
(그래서 가상머신으로 테스트해봤다.)

server에서와 같이 keystore를 만들어야 한다.
하지만, pc(java)에서 keystore 방식(?)이 JKS인데 안드로이드에서는 BKS로 해야 한다. (여러곳을 찾아보니 사람들이 그렇다고 하네요;;)

그래서 JKS로 keystore를 만들고 변환 툴 (portecle-1.5)을 이용해서 BKS로 바꾸려 했으나... 무슨 key길이가 어쩌구저쩌구 하면서 오류를 내는데....


21294041526F48973EF620


이 문제는 검색을 해보니 jce_policy-6을 다운받아서 내용을 
java/jre/lib/secure 하위 파일에 붙여넣으면 된다고 하는데.. 역시 나는 안되더라.

그래서 바로 BKS로 만들어서 하는 방법을 찾다보니
역시 해본사람이 있다.

참조 : http://blog.brent.kr/25

2. keystore 파일 생성
    1) http://bouncycastle.org/latest_releases.html 에서 
설치된 JDK에 해당하는 bcprov-jdkXX-XXX.jar 파일을 다운 로드 받는다.

    2) *.bks 파일을 생성한다.

keytool -importcert -v -trustcacerts -file c:/k/server.cer -alias server -keystore c:/k/client.bks -provider org.bouncycastle.jce.provider.BouncyCastleProvider -providerpath "bcprov-jdk16-145.jar" -storetype BKS -storepass changeit

(인증서는 기존에 추출해 놓은 server.cer, -providerpath이부분은 파일을 keytool있는곳에 같이 두었다.) 

3. *.bks 파일을 안드로이드 프로젝트에서 /res 폴더 밑에 적당히 집어 넣어 준다.(그래야 R.class에 자동으로 등록 되어 사용 할 수 있다)


  1. import java.io.BufferedWriter;  
  2. import java.io.OutputStream;  
  3. import java.io.OutputStreamWriter;  
  4. import java.io.PrintWriter;  
  5. import java.net.Socket;  
  6. import java.security.KeyStore;  
  7.   
  8. import javax.net.ssl.KeyManagerFactory;  
  9. import javax.net.ssl.SSLContext;  
  10. import javax.net.ssl.SSLSocket;  
  11. import javax.net.ssl.SSLSocketFactory;  
  12. import javax.net.ssl.TrustManager;  
  13. import javax.net.ssl.TrustManagerFactory;  
  14.   
  15. import android.os.Bundle;  
  16. import android.app.Activity;  
  17. import android.util.Log;  
  18. import android.view.Menu;  
  19. import android.view.View;  
  20. import android.view.View.OnClickListener;  
  21. import android.widget.Button;  
  22. import android.widget.EditText;  
  23. import android.widget.TextView;  
  24.   
  25. public class MainActivity extends Activity {  
  26.   
  27.     @Override  
  28.     protected void onCreate(Bundle savedInstanceState) {  
  29.         super.onCreate(savedInstanceState);  
  30.         setContentView(R.layout.main);  
  31.           
  32.         Button btn = (Button)findViewById(R.id.Button01);  
  33.           
  34.         btn.setOnClickListener(new OnClickListener(){  
  35.         public void onClick(View v){  
  36.             Thread cThread = new Thread(new TCPClient());  
  37.             cThread.start();  
  38.         }  
  39.         });  
  40.           
  41.     }  
  42.   
  43.     @Override  
  44.     public boolean onCreateOptionsMenu(Menu menu) {  
  45.         // Inflate the menu; this adds items to the action bar if it is present.  
  46.         getMenuInflater().inflate(R.menu.main, menu);  
  47.         return true;  
  48.     }  
  49.   
  50.     public class TCPClient implements Runnable {  
  51.         public void run() {  
  52.              try {  
  53.                                    
  54.                  Log.d("TCP""C: Connecting...");  
  55.   
  56.                 char[] passphrase = "changeit".toCharArray();  
  57.                 KeyStore keystore = KeyStore.getInstance("BKS");  
  58.                 keystore.load(getResources().openRawResource(R.raw.cl), passphrase);  
  59.                 TrustManagerFactory tmf = TrustManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());  
  60.                 tmf.init(keystore);  
  61.                 SSLContext context = SSLContext.getInstance("TLS");  
  62.                 TrustManager[] trustManagers = tmf.getTrustManagers();  
  63.                 context.init(null, trustManagers, null);  
  64.                 SSLSocketFactory sf = context.getSocketFactory();  
  65.                 Socket socket = sf.createSocket("203.255.217.214", 9999);  
  66.                    
  67.                  String message = "Hello from Client";  
  68.                  try {  
  69.                      Log.d("TCP""C: Sending: '" + message + "'");  
  70.                      //PrintWriter out = new PrintWriter( new BufferedWriter( new OutputStreamWriter(socket.getOutputStream())),true);  
  71.                      //PrintWriter out = new PrintWriter(new OutputStreamWriter(socket.getOutputStream()), true);  
  72.                      OutputStream outputstream = socket.getOutputStream();  
  73.                      OutputStreamWriter out = new OutputStreamWriter(outputstream);  
  74.                      BufferedWriter bufWriter = new BufferedWriter(out);  
  75.                        
  76.                      bufWriter.write(message);  
  77.                      bufWriter.flush();  
  78.                        
  79.                        
  80.                      //out.println(message);  
  81.                      Log.d("TCP""C: Sent.");  
  82.                      Log.d("TCP""C: Done.");  
  83.                        
  84.                  } catch(Exception e) {  
  85.                      Log.e("TCP""S: Error", e);  
  86.                   } finally {  
  87.                     socket.close();  
  88.                   }  
  89.              } catch (Exception e) {  
  90.                   Log.e("TCP""C: Error", e);  
  91.              }  
  92.         }  
  93.     }  
  94.   
  95. }  


버튼을 만들어서 실행되게 했다.

결과화면(console창)


2620804A526F4B152230BD

Logcat

2126A83C526F4B5301A2D0