티스토리 뷰

공장 (factory)/- Programming..

[Java] keystore/truststore 생성, SSL 사용 예.

공부하는 나부랭이, 무중력고기 2014.01.29 19:11

   처음엔 SSL(Secure Sockets Layer)이 뭔지 개념부터 잡기가 어려웠는데, "미닉스의 작은 이야기들"이란 블로그에 연재된 웹툰의 도움을 많이 받았다. (__) 감사합니다.

   바로 이곳 ☞ http://minix.tistory.com/395

   암호화에 관해 가장 쉽게 설명되어 있는 곳이 아닌가 싶다.

   이 분이 그린 웹툰을 모아서 출판까지 했는데, 관심 있는 사람은 사서 보길 바란다.

   



   초간단하게 설명하자면 SSL은 RSA의 업그레이드 판이고 TLS(Transport Layer Security)는 SSL 3.0의 표준화 버전이다.


   실질적으로 SSL을 사용해보는 데에 있어서 도움을 받은 사이트들은 다음과 같다.

   정보들이 조각조각 흩어져 있어서 이거 하느라고 애좀 먹었다.


   참고한 사이트 ☞ http://stilius.net/java/java_ssl.php , http://kdarkdev.tistory.com/238?srchid=BR1http://kdarkdev.tistory.com/238http://www.javanna.net/2011/07/common-ssl-issues-in-java , https://sites.google.com/site/ssljavaguide/example-code/one-way-ssl   이외에도 미치도록 많이 찾아봤지만.. 여기까지만.



   자 그럼 최대한 친절하고 쉽게 설명하도록 하겠다.




   1. server와 client의 keystore(private key)를 생성한다.


   cmd 창에서 keytool을 이용해서 만든다. keytool은 Java/jdk1.7.0_51/bin 폴더에 있다.


keytool -genkey -v -keystore <keyName> -alias <alias> -keyalg RSA -keysize 2048 -validity 10000


   validity가 10000일 경우 하루를 뜻한다.


   내 경우 저런 식으로

keytool -genkey -v -keystore server -alias server -keyalg RSA -keysize 2048 -validity 10000   <-- 서버

keytool -genkey -v -keystore client -alias client -keyalg RSA -keysize 2048 -validity 10000   <-- 클라이언트

   이렇게 2개를 생성했다.



   2. 만들어놨던 2개의 keystore(server, client)를 이용해서 truststore(public key)를 뽑아낸다.


keytool -export -alias <alias> -keystore server -rfc -file <cerFileName>.cer


   keytool -export -alias server -keystore server -rfc -file trustServer.cer <-- 서버

   keytool -export -alias client -keystore client -rfc -file trustClient.cer <-- 클라이언트




   3. Default truststore list인 cacerts파일(Java/jdk1.7.0_51/jre/lib/security에 위치해 있음)에 만들어놨던 2개의 keystore를 추가한다.


   마찬가지로 cmd 창에서 다음의 명령어를 입력한다.


keytool -import -alias <alias> -file <cerFileName>.cer -keystore cacerts –storepass changeit


keytool -import -alias trustServer -file trustServer.cer -keystore cacerts –storepass changeit <-- 서버

keytool -import -alias trustClient -file trustClient.cer -keystore cacerts –storepass changeit <-- 클라이언트


   3번 작업은 서버로 쓸 컴퓨터와 클라이언트로 쓸 컴퓨터 모두 작업을 해줘야 한다.


   근데 사실 디폴트 리스트인 cacerts에 keystore를 추가하는 방법은 그리 좋지 않은 방법이라고 한다. 새로운 custom truststore list 파일을 만들어서 하는 방법을 알게 되면 내용을 보충하도록 하겠다.



   4. Server 측 Java 코딩


import javax.net.ssl.SSLServerSocket;
import javax.net.ssl.SSLServerSocketFactory;
import javax.net.ssl.SSLSocket;

public class EchoServer {
	
	public static void main(String[] args) {
		
		try{
			// 만들어놨던 server keyStore 파일을 임의의 폴더에 위치시키고 아래와 같이 설정해준다.
			System.setProperty("javax.net.ssl.keyStore","C:\\Program Files (x86)\\Java\\jdk1.7.0_51\\bin\\server");
			
			// password는 keyStore를 만들 때 입력했던 것.
			System.setProperty("javax.net.ssl.keyStorePassword","thisispassword");
			
			// 디버깅을 위해 아래와 같이 설정.
			System.setProperty("javax.net.debug","ssl");
			
			System.out.println("***********keyStore : " + System.getProperty("javax.net.ssl.keyStore"));
			System.out.println("***********trustStore : " + System.getProperty("javax.net.ssl.trustStore"));
			
			// 서버 소켓 팩토리 생성.
			SSLServerSocketFactory sslserversocketfactory = (SSLServerSocketFactory)SSLServerSocketFactory.getDefault();
			
			// 서버 소켓 생성. 1115는 포트 번호.
			SSLServerSocket sslserversocket = (SSLServerSocket)sslserversocketfactory.createServerSocket(1115);
			System.out.println("Wating Connection");
			
			// 클라이언트가 언제 접속할지 모르니 항상 대기.
			while(true){
				SSLSocket socket = (SSLSocket)sslserversocket.accept();
				// 데이터 읽는 부분은 쓰레드로 처리.
				ThreadServer thread = new ThreadServer(socket);
				thread.start();
			}
			
		}catch(Exception ex){
			System.out.println(ex);
		}
		
	}
	
}


import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;

import javax.net.ssl.SSLSocket;

public class ThreadServer extends Thread {

	private SSLSocket socket;
	private InputStream input;
	private InputStreamReader reader;
	private BufferedReader br;

	public ThreadServer(SSLSocket socket){
		this.socket = socket;
	}

	@Override
	public void run() {
		
		try{
			String fromClient = null;
			input = socket.getInputStream();
			reader = new InputStreamReader(input);
			br = new BufferedReader(reader);
			
			while((fromClient = br.readLine())!=null){
				System.out.println(fromClient);
				System.out.flush();
			}
			
		}catch(Exception e){
		}
		
	}
	
}



   5. Client 측 Java 코딩


import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;

import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;

public class EchoClient {
	
	public static void main(String[] args) {
		
		try {
			
			// 소켓 팩토리 생성
			SSLSocketFactory sslsocketfactory = (SSLSocketFactory) SSLSocketFactory.getDefault();
	
			// 만들어놨던 server keyStore 파일을 임의의 폴더에 위치시키고 아래와 같이 설정해준다. (클라이언트에도 keyStore 파일이 있어야 함)
			System.setProperty("javax.net.ssl.keyStore", "\\home\\hduser\\workspace\\newkeys\\client");
			
			// password는 keyStore를 만들 때 입력했던 것.
			System.setProperty("javax.net.ssl.keyStorePassword", "thisispassword");
			
			// 디버깅을 위해 아래와 같이 설정.
			System.setProperty("javax.net.debug", "ssl");
			
			System.out.println("&&&&&& keyStore : " + System.getProperty("javax.net.ssl.keyStore"));
			System.out.println("&&&&&& trustStore : " + System.getProperty("javax.net.ssl.trustStore"));
			
			// 소켓에 서버의 IP와 포트 번호를 입력해준다.
		    SSLSocket sslsocket = (SSLSocket) sslsocketfactory.createSocket("192.111.1.111", 1115);

			// 서버로 보낼 파일의 경로와 이름.
		    String dir = "/home/username/workspace/SSLTest/src/test";
		    String fileName = "test.txt";
			
		    InputStream inputstream = new FileInputStream(new File(dir, fileName));
		    InputStreamReader inputstreamreader = new InputStreamReader(inputstream);
		    BufferedReader bufferedreader = new BufferedReader(inputstreamreader);
		    
		    OutputStream outputstream = sslsocket.getOutputStream();
		    OutputStreamWriter outputstreamwriter = new OutputStreamWriter(outputstream);
		    BufferedWriter bufferedwriter = new BufferedWriter(outputstreamwriter);

		    String string = null;

		    while ((string = bufferedreader.readLine()) != null) {
		        bufferedwriter.write(string + '\n');
		        bufferedwriter.flush();
		    }
		    
		} catch (Exception exception) {
		    exception.printStackTrace();
		}
		
	}
	
}



   작업이 모두 마치면, 서버를 돌리고 클라이언트를 접속해보자. 그럼 서버의 콘솔 창에 데이터가 무사히 들어옴을 확인할 수 있다.




   형광펜으로 칠한 부분이 클라이언트에서 txt 파일로 보낸 데이터다.



저작자 표시 비영리 변경 금지
신고
댓글
댓글쓰기 폼
Total
848,882
Today
92
Yesterday
788
«   2017/10   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31        
글 보관함