블로그 내 검색

2010. 7. 23.

PKI - Public Key Interface


암호화는 코드 및 암호를 통해 정보를 보호하는 기술.
코드는 정보 변경 방법을 모르는 상태로 읽을 수 없도록 하기 위해 정보를 체계적으로 변경하는 프로세스이다.
정보를 코드로 변경하는 작업을 "암호화" 코드를 정보로 되돌리는걸 "해독"이라고 한다.
암호화를 할때 사용된 수단 혹은 정보를 키라고 하며 이때 사용된 방식을 암호화 알고리즘이라고 한다.

정리하면

- 암호화 : 정보를 코드로 변환
- 해독 : 코드를 정보로 변환
- 키 : 정보를 코드로 변환할 때 사용된 정보
- 암호화 알고리즘 : 정보를 코드로 변경할 때 사용된 방식

예를 들어...

A는 "Hello World" 라는 정보를 B에게 전송한다.
이때 A는 암호화 키로서 l이라는 알파벳을 모두 A로 바꾸는 키를 사용하였고 이걸 심플 알고리즘이라고 이름붙였다.
B는 코드로서 "HeAAo WorAd" 라는 코드를 받았다. 애초에 서로 가진 키와 알고리즘을 통해 이 코드는 A를 l로 바꾼 것임을 알고, 암호 해독을 실행하여 "Hello World" 라는 정보를 얻어냈다.

이러한 암호화 방식을 대칭 키 암호화라고 한다.
A와 B가 동일한 키를 가지고 있기 때문이다. 심플하지만 이것이 앞으로 나올 암호화의 기본이 된다.

좀더 발전된 형태의 암호화가 선보였는데, 1976년에 Whitfield DiffeMartin Hellman에 의해 공개 키 암호화가 발표되었다.
이 암호화는 두개의 키를 사용한다. 

 - 하나는 개인키(비밀키)로서 오로지 자신만 소유한다.
 - 하나는 공개키(공유키)로서 외부에 공개해 둔다.
 - 두개의 키는 수학 알고리즘으로 묶여 있다.

이제 다시 예를 들자.

A는 B에게 메시지를 보내기 위해 B에게 공개키를 요구한다.
B는 A에게 자신이 가진 개인키와 쌍을 이루고 있는 공개 키를 공개하고, 
A는 그 키를 받아 B에게 보낼 정보를 암호화하여 코드로 만든다.
B는 코드를 받으면 자신의 개인 키로 해독, A가 보내려 했던 정보를 볼 수 있다

이 암호화 방식으로 얻어지는 이점은 정보의 교환 말고 여러가지가 있다.
그중 대표적인 건 디지털 서명이라는 송신자를 확인할 수 있는 이점이다.
개인키는 오로지 하나의 소유자만이 소유할 수 있기에 만일 개인키로 암호화한 코드는 그 개인이 암호화했다는걸 증명하는 서명과 같이 동작한다.


디지털 서명의 방법의 플로우는

정보를 자신의 개인키로 암호화하여 암호화문과 별도로 메시지 헤더등에 추가한다. 이걸 서명이라고 한다. 
그리고 보낼 사람의 공개키로도 정보를 암호화한다. 
받는 측은 메시지 송신자의 진위여부를 파악하기 위해 송신자의 공개키로 헤더의 서명 암호화를 해독한다.
그리고 정보또한 자신의 개인키로 해독한다. 
두 내용이 일치하면 송신자가 조작되지 않았음을 알 수 있다.

여기서...정보 외에 헤더에 추가하는 서명은 부하등의 이유로 먼저 본문을 약속된 해시 알고리즘으로 해쉬한뒤 서명을 생성하는게 보통이다.

여기서 주의할 점이 있다.
일반적인 공개키 암호화 방식은 복잡한 수학 연산에 의해 부하가 상당하다. 
이 부하를 피하기 위해서 대칭키 암호화와 섞어 사용하는게 보통이다.

그렇다. 공개키 암호화 방식으로 대칭키 자체를 암호화해 보내는 방법이다.
키 자체만을 암호화하기 때문에 부하가 상대적으로 비용이 적다.

여기까지 설명한 방법을 모두 합친 암호화 및 서명 플로우는 다음과 같다.

1. 정보를 해시한뒤 그 값을 자신의 개인키로 암호화한다.
2. 그 결과를 보낼 메시지에 추가한다. 이것을 서명이라고 한다.
3. 일회용의 대칭키를 생성한다.
4. 대칭키로 정보를 암호화하여 보낼 메시지에 추가한다.
5. 받는 사람의 공개키를 획득한다.
6. 받는 사람의 공개키로 일회용의 대칭 키를 암호화한다.
7. 그 결과를 보낼 메시지에 추가한다.
8. 수신자는 메시지에서 서명, 암호화된 일회용 대칭키, 암호화된 코드를 확인하고 분리한다.
9. 수신자의 개인키로 암호화된 일회용 대칭키를 해독한다.
10. 해독된 대칭 키로 코드를 해독한다.
11. 보낸 사람의 공개키를 획득한다.
12. 서명을 보낸 사람의 공개키로 해독하고 그 결과를 위에서 해독된 코드의 정보를 해시하여 비교한다.
13. 값이 일치하면 메시지와 송신자가 유효한 것이 증명된다.

2010. 7. 22.

파일 MimeType 을 구별하는 다양한 방법

파일의 마임 타입(Mime-Type)은 정말 다양하며 때때로 그걸 구별해야 할 필요가 생긴다.

문제는 받아온 파일의 확장자가 jpg라고 그 파일마저 jpg이진 않다는 것이다.
혹은 확장자가 없거나 하는 일도 있어 그 파일의 정체를 알고 싶다면 다른 방법을 써 봐야 한다.

요새는 프로그램들이 좋아져서 파일에 대고 연결프로그램으로 대충 열기를 시도해보면 열리긴 하지만, 이걸 프로그램에 포함시키기엔 무리가 있다.

마임 타입을 구별할 수 있는 방법에 대해 조금 알아보자.


1. (웹서버 다운로드의 경우) HTTP 헤더의 컨텐트 타입 값을 검사

이 방법은 어떻게보면 아주 순수한 작업이다. 웹 서버를 매우 신뢰할 때 할 수 있는 방법이다.
그러나 세상은 그리 순수하지 않고 IT의 세계는 더욱 진흙탕 바닥이다.
HTTP 헤더는 그냥 서버측에서 간단한 조작만으로 변경이 가능하다. 응답하는 데이터가 image/gif 인데도 응답을 text/plain 으로 응답을 조작할 수 있다.

이 방법은 타입 구별이 그저 "옵션" 일 경우에나 적합한 방법이라 볼 수 있다.


2. 파일 컨텐트의 바이트를 검사

이 방법이 역시 제일 정확한 방법이다.
모든 파일(text 파일 제외)에는 이 파일이 어떠한 포맷이라는걸 알려주는 고유의 시그니쳐 바이트가 존재한다.
그 길이는 파일마다 다르며, 종류또한 파일의 포맷만큼 많다.

예를 들어 image/jpg 의 파일을 바이트스트림으로 읽어 표시하면 다음과 같은 헥스값을 볼 수 있다.

FF D8....

어떠한 종류의 JPG 파일도 반드시 저것으로 시작한다 는걸 보장할 수 있다.

그러나 여기서 문제가 또 생긴다.
어느 포맷이 어느 시그니쳐를 가지는가에 대한 사전정보가 없다.
그리고 그 포맷의 앞 어느 바이트까지가 교유한 시그니쳐인가에 대한 정보또한 없다.

물론 파일 포맷을 모두 수집하여 하나하나 분석한뒤 자신의 사전을 구축하고 그걸 토대로 프로그래밍할 수 있다. 그러나 놀 시간도 없는 판국에 이러한 짓을 하기보다는 위대한 선구자들의 경험을 빌려보자.

참고로 파일 시그너쳐 테이블이 나온 페이지를 소개해둔다. 이곳을 클릭해보자

이제 Java에서 MimeType을 구별하는 방법에 대해 알아보자.

3. Java Code 사용한 구별법

몇 가지 파일 타입을 구별하는 방법이다.

= MimetypesFileTypeMap을 사용
File f = new File("gumby.gif");
System.out.println(new MimetypesFileTypeMap().getContentType(f));

= URLConnection 을 사용하는 방법 (굉장히 느리다! 주의가 필요...)
import java.net.*;

public class FileUtils{
    public static String getMimeType(String fileUrl)
    throws java.io.IOException, MalformedURLException 
    {
        String type = null;
        URL u = new URL(fileUrl);
        URLConnection uc = null;
        uc = u.openConnection();
        type = uc.getContentType();
        return type;
    }

    public static void main(String args[]) throws Exception {
        System.out.println(FileUtils.getMimeType("file://c:/temp/test.TXT"));

        // FileNameMap을 사용하는 우회적 방법...이건 좀 빠른편
        //FileNameMap fileNameMap = URLConnection.getFileNameMap();
        //String contentType = fileNameMap.getContentTypeFor(text.txt);
    }
}

= Apache Tika 을 사용하는 방법
String mimeType = null;
try {
    Tika tika = new Tika();
    mimeType = tika.detect(file);
} 
catch (Exception e) {
    System.err.println("오류");
}
System.err.println(mimeType);
위 세가지 방법중 추천할만한건 역시 Tika를 사용한 파싱 방법이다.
다양한 파일을 구분해낼 수 있다.

Apache Tika 의 공식 프로젝트 문서는 이곳(http://tika.apache.org/)으로.
웹 크롤러 작업시 꽤 도움을 받았다.

2010. 5. 26.

POJO

Plain Old Java Object

앞자만 따 와서 POJO 라고 한다.
정의를 해보자면 Plain Old Java Object의 두문자어이다.

이 용어는 2000년 9월 Martin Fowler, Rebecca Parsons, Josh Meckenzie에 의해 이름지어졌는데....

마틴 파울러는 이런말을 했다고 한다.

" 왜 사람들이 간단한 보통 자바객체를 사용하지 않을까 생각했는데 그건 심플한 객체에 멋진 이름이 없어서라고 생각한다. 그래서 사람들에게 이름을 주려고 한다."

라고 해서 탄생한 이름이 POJO이다.

특정 클래스를 상속하지 않는다.
특정 인터페이스를 구현한 concrete 객체가 아니다.
특정 어노테이션을 이용한 객체가 아니다.

주의할 점은 상족 혹은 구현등이 안된다고 해서 Runable등의 구현 목적과 자바 기본 패키지의 클래스를 이용한 방법까지 POJO가 아니라고 할 수 없다. 특정 플랫폼이나 프레임워크에 종속적이지 않은 클래스 구현은 POJO의 범주에 들어간다고 볼 수 있겠다.