SSISO Community

시소당

MD5방식을 이용한 암호화 및 복원화

자~ 지금까지는 푸념이었고 오늘 쓰게 되는 아티클은 보통 사이트에서 패스워드를 저장하려고 할때 암호화해서 넣는 방법중의 MD5(Message Digest)를 자바로 구현하여 집어넣는 것을 만들려고 합니다. 보통의 금융권의 사이트들이나 일반사이트들은 금융감독원에서 ISMS라고 해서 보안정책을 하달하여 "이것대로 안만들면 죽는줄 알어~"라는 지침이 하달되는데 그 기준을 맞추기 위하여 이미 아래의 아티클에서 설명이 되었었던 암호화등의 방식을 적용한 H/W or S/W를 설치하여 그 기준에 부합하게 적용을 하게 됩니다.

위에서 이야기한 MD5는 또 어디서 봤을까요? 어? 못봤어요? 리눅스에 조금만 관심이 있다던지 시스템을 조금 안다고 한다면 보통의 unix운영체제에서 MD어쩌구 저쩌구 라고 보셨을텐데..
아구~ 만약 못보았다면 공부좀 열심히 하셔야 겠습니다.

그럼 아파치에서 사용자 인증을 위한 htpasswd는 보셨나요? 디렉토리에 user리스트등을 걸어서 해당 사용자에 대한 접근을 시도하도록 하는 거 말이죠~ 어라? 이것도 구경못해봤다구요?

홍.... 그럼 진짜 쌍코피터지게 공부하셔야 겠군요. 하기사 이런것 몰라도 먹구 사는데 지장은 없습니다만 그래도 안다면 어디가서 아는 척은 할수도 있겠지요.

자 그럼 대체 MD5가 무엇인지를 알고서 넘어가야 왜 쓰는지를 알수 있겠지요? 알아봅시다.

▶ MD2, MD4, MD5란 무엇인가?

MD2, MD4, MD5는 Rivest가 개발한 메시지 요약 알고리즘이며, 128비트의 메시지 요약을 생성해냅니다. MD2는 8비트 컴퓨터용으로 최적화되었고, Md4와 Md5는 32비트 컴퓨터용으로 되어있다는 특징을 가지고 있습니다. 얘네들 같은 경우는 대표적인 해쉬함수측에 포함되어져 있는데, 해쉬함수란놈은 자바에서처럼  스트링을 일정한 길이의 해쉬코드로 출력을 내보내게 되는데 얘들은 두가지 성질을 만족해야 하는 특징을 가지고 있습니다.
첫째로 만들어진 해쉬코드를 보고 해당 해쉬코드를 만들었던 스트링을 찾아내지 못해야 하며, 두번째는 주어진 스트링에 대하여 같은 해쉬코드를 생성하는 또 다른 스트링을 찾아내지 못해야
한다는 것입니다.

보 통의 해쉬함수들은 SNEFRU, MD2, MD4, MD5, SHA등등이 있는데 MD4가 1992년에 아주 똑똑한 사람에 의하여 해독이 되어 버려서 MD5로 비트길이를 발전시키기에 이르렀다네요..SHA같은 경우도 MD4에서 파생된 160비트 해쉬코드를 만드는 놈인데 보면 대략 MD5와 비슷한 형태를 가지고 있습니다.

MD5같은 경우 사실 SHA보다 32비트가 작은 128비트를 가지고 있지만 빠르고, 쉬우며, 간결하다는데 특징을  둘수 있겠네요. 알려진 결과로는 SHA보다 MD5의 수행성능이 약 25%정도 빠르다는 특징을 가지고 있습니다.

SHA같은 경우는 SMTP서버나 기타등등의 데몬등에서 사용자에 대한 내용등을 옵션으로 선택하여 사용할수도 있게하고 있죠.

▶ 자바에서의 MD5의 사용

어 떤 방식의 해쉬결과가 나오는지 알고 싶다면 옆에 있는 컴퓨터중에 linux같은게 있으면 열어보세요. 콘솔로 /etc/passwd파일을 열어서 해당 사용자들에 대한 패스워드가 어떻게 입력이 되어져 있는지 보세요. cbWWy0LuJU90FgQ9GE/JcA== 등등의 문자로 장식을 하고 있는 게 보일겁니다.

자 이제 그러한 해쉬함수를 이용한 결과값을 자바측에서 얻어낼 것인데, 기본적인 MD5알고리즘을 이용하여 자바코드를 짜게 된다면 약 400라인정도의 byte연산을 통하여 결과값을 얻어낼 수
있습니다. 하지만 알고리즘 이해하고 그걸 짜실랍니까?
보통의 인터넷을 뒤진다고 했을때 지금 여러분은 빨리 찾고 빨리 적용하고 싶어서이기 때문에 API를 이용하여 만들어내는 방법을 더 선호하겠죠~ 연구자 기질이 있다면 그 원리를 알고 싶어할지는 몰라도 말이죠~

시작해보죠~
자바에서 java.security패키지에 보면 여러가지 보안에 관련된 클래스를 사용할 수 있도록 구성되어 있습니다. 거기에 MessageDigest클래스가 해당 알고리즘을 이용하여 digest를 할 수 있도록 구성해줍니다.

보통의 Util을 만든다하면 개발되는 프레임웍의 util package에 위치할 것이기 때문에 공통으로
사용할 수 있도록 클래스를 구성합니다

▶ SecurityUtil.java

import java.security.*;

public class  SecurityUtil {

    /**
     * byte[] ret = HashUtil.digest("MD5", "abcd".getBytes());
     *  처럼 호출
     */
    public static byte[] digest(String alg, byte[] input) throws NoSuchAlgorithmException {
        MessageDigest md = MessageDigest.getInstance(alg);
        return md.digest(input);
    }

    public static String getCryptoMD5String(String inputValue) throws Exception {
        if( inputValue == null ) throw new Exception("Can't conver to Message Digest 5 String value!!");
        byte[] ret = digest("MD5", inputValue.getBytes());
        String result = Base64Util.encode(ret);   
        return result;
    }
}

위 의 클래스에 해당 스트링값을 던지게 되면 실제 digest된 결과 문자열을 되돌려 줄수 있도록 처리하였는데 이것이 끝이냐~ 아닙니다. 실제 던져진 해쉬함수에 의한 결과를 System.out으로 찍게 되면 찌그러진 코드형태로 나오게 되는데 이것을 우리 눈으로 비교하여 String문자비교를 통하여 추후 사용할 수 있도록 하려면 Base64 인코딩을 시도해야 합니다.

그 유틸리티 클래스는 아래와 같습니다.

▶ Base64Util.java

import sun.misc.*;
import java.io.*;

/**
*

* Filename  : Base64Util.java

* Class : Base64Util

* Function : Base64 Encoding/Decoding을 수행하는 클래스

* Comment :

* History : 2000-08-16 2:48오후

*


* @version  1.0
* @author carouser
*/
public class Base64Util {

    public Base64Util() {}

    /**
     * Base64Encoding을 수행한다. binany in ascii out
     *
     * @param encodeBytes encoding할 byte array
     * @return encoding 된 String
     */
    public static String encode(byte[] encodeBytes) {
       
        BASE64Encoder base64Encoder = new BASE64Encoder();
        ByteArrayInputStream bin = new ByteArrayInputStream(encodeBytes);
        ByteArrayOutputStream bout = new ByteArrayOutputStream();
        byte[] buf = null;

        try{
            base64Encoder.encodeBuffer(bin, bout);
        } catch(Exception e) {
            System.out.println("Exception");
            e.printStackTrace();
        }
        buf = bout.toByteArray();
        return new String(buf).trim();
    }

    /**
     * Base64Decoding 수행한다. binany out ascii in
     *
     * @param strDecode decoding할 String
     * @return decoding 된 byte array
     */
    public static byte[] decode(String strDecode) {
       
        BASE64Decoder base64Decoder = new BASE64Decoder();
        ByteArrayInputStream bin = new ByteArrayInputStream(strDecode.getBytes());
        ByteArrayOutputStream bout = new ByteArrayOutputStream();
        byte[] buf = null;

        try {
            base64Decoder.decodeBuffer(bin, bout);
        } catch(Exception e) {
            System.out.println("Exception");
            e.printStackTrace();
        }

        buf = bout.toByteArray();

        return buf;

    }
}


String passwd = SecurityUtil.getCryptoMD5String("Carouser");

출처 : http://www.javapattern.info/?page=3

869 view

4.0 stars