본문으로 바로가기

SSL

category 개발이야기/Android 2017. 10. 8. 15:22
반응형

기본 원리

대칭키
1. 암호화와 복호화를 위해서는 대칭키를 이용한다.
2. 즉 서로 대칭키만 알고 있다면 암호화해서 보내고 암호화된 데이터를 복호화 할 수 있다.

공개키와 개인키
1. 수학적으로 복잡하게 공개키와 개인키를 만든다. -> 두개는 한쌍인다.
2. 공개키로 암호화 하면 개인키로 복호화가 가능, 개인키로 암호화 하면 공개키로 복호화 가능
3. 개인키는 보관하고 공개키는 다른사람에게 공개한다.
4. 다른사람이 나의 공개키로 암호화 해서 나에게 보내면 개인키로 해독할 수 있다.
5. 나 역시 다른 사람의 공개키로 암호화 해서 보내면 상대방이 자신의 개인키로 해독할 수 있다.
6. 공개키와 개인키는 암호화와 복호화 하는데 많은 시간이 걸린다.

세 키의 조합
1. 모든 데이터를 공개키와 개인키로 주고 받는다면 암호화와 복호화에 시간이 많이 걸린다.
2. 따라서 공개키로 대칭키만 암호화하여 보낸다.
3. 암호화된 대칭키를 받은 수신자는 자신의 개인키로 복호화 하여 대칭키를 받는다.
4. 이후로는 대칭키를 사용하여 서로 암호화/복호화 한다.

공인인증서
1. 돌아다니는 공개키가 진짜인지 확인할 수 없다.
2. 사이트는 자신의 정보와 공개키를 인증 기관에 보낸다.
3. 인증기관은 자신의 개인키로 사이트의 정보와 공개키를 암호화 한다.
4. 인증기관은 자신의 공개키를 웹브라우저에 제공한다.
5. 웹브라우져는 기본적으로 인증기관의 대칭키를 가지고 있다.

인증서를 이용한 SSL 사용
1. 사이트에 접속을 요청한다.
2. 사이트는 인증기관에서 받은 인증서를 보낸다.
3. 웹브라우저는 탑재된 인증기관의 공개키로 인증서를 복호화 한다.
4. 사이트의 정보와 공개키가 복호화 되면, 사용자는 해당 공개키로 대칭키를 암호화 하여 보낸다.
5. 암호화된 데이터를 받은 사이트는 자신의 개인키로 복호화 하여 대칭키를 얻는다.
6. 사용자와 사이트는 대칭키로 암호화/복호화를 진행한다.

아래 사이트에서 웹툰으로 flow를 쉽게 이해할 수 있다.
http://minix.tistory.com/395


Android에서 SSL의 구현

https://developer.android.com/training/articles/security-ssl.html#CommonProblems

공인된 CA를 사용하는 경우 HttpUrlConnection을 사용하면 내부적으로 자동 처리되나, 아래와 같은 경우 SSLHandShakeException을 일으킨다.

1. Android system에서 알지 못하는 (unknown) 인증서인 경우
- Android에서 인증된 인증서가 아니거나, SDK 버전이 구버전인 경우
2. 서버에서 자체 서명한 인증서인 경우
3. 중간 CA에 생략되어 Android에서 인식 못하는 경우

인증서를 따로 생성해서 Client에서 등록하여 사용하는 방법

1. 수신받은 inputStream에서 cert 파일 추출 및 certification 생성
2. keyStore를 생성하여 certification set
3. trustManager 생성하여 keyStore로 init
4. SSLcontext를 생성하여 trustManager로 init
5. HttpUrlConnection에 SSLSocketFactory에 생성된 context의 socketFactory를 set


예제코드

// Load CAs from an InputStream
// (could be from a resource or ByteArrayInputStream or ...)
CertificateFactory cf = CertificateFactory.getInstance("X.509");
// From https://www.washington.edu/itconnect/security/ca/load-der.crt
InputStream caInput = new BufferedInputStream(new FileInputStream("load-der.crt"));
Certificate ca;
try {
    ca = cf.generateCertificate(caInput);
    System.out.println("ca=" + ((X509Certificate) ca).getSubjectDN());
} finally {
    caInput.close();
}

// Create a KeyStore containing our trusted CAs
String keyStoreType = KeyStore.getDefaultType();
KeyStore keyStore = KeyStore.getInstance(keyStoreType);
keyStore.load(null, null);
keyStore.setCertificateEntry("ca", ca);

// Create a TrustManager that trusts the CAs in our KeyStore
String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
tmf.init(keyStore);

// Create an SSLContext that uses our TrustManager
SSLContext context = SSLContext.getInstance("TLS");
context.init(null, tmf.getTrustManagers(), null);

// Tell the URLConnection to use a SocketFactory from our SSLContext
URL url = new URL("https://certs.cac.washington.edu/CAtest/");
HttpsURLConnection urlConnection =
    (HttpsURLConnection)url.openConnection();
urlConnection.setSSLSocketFactory(context.getSocketFactory());
InputStream in = urlConnection.getInputStream();
copyInputStreamToOutputStream(in, System.out);


반응형

'개발이야기 > Android' 카테고리의 다른 글

Android Service간 통신 #1  (6) 2017.10.10
Android 애니메이션#2 - Tweened Animation  (2) 2017.10.09
Android 애니메이션#1 - Thread & ImageSwitcher  (2) 2017.10.08
Android 프로젝트 Stan에서 보기  (0) 2017.10.07
시작  (0) 2017.09.09