개발관련/암호화 2009. 12. 31. 15:39

해쉬와 같은 단방향 암호화 알고리즘은 다양한 보안영역에 활용된다.
그 활용의 하나로 해쉬 알고리즘을  이용한 패스워드 암호화 방법에 대해서
설명하고자 한다.
최근 개인정보보호에 대한 이슈가 더욱 즁요하게 제기되면서 사용자패스워드와 같은
정보를 암호화하여 정보상에 유통하고 이를 안전하게 보관해야하는 것이 필수 조건이다.
개인의 패스워드를 입력받아 서버를 통하여 데이터베이스까지 안전하게 전송하기 위해서는
데이터 구간의 암호화가 필수이지만 해쉬 알고리즘을 잘 이용하면 구간 암호화를 굳이 사용하지
않고도 이러한 효과를 얻을 수 있다.

다음의 시나리오는 실제 구현한 프로세스이다.

 

<해쉬알고리즘을 이용한 패스워드 암호화 시나리오>

 

1. A라는 쇼핑몰 홈페이지에서 입력받은 패스워드를 해쉬한다

HTML>
<HEAD>
<script language=javascript src="sha1.js"></script>
<SCRIPT LANGUAGE="JavaScript">
<!--

function AS(s){
   //var s = form.A.value;
   alert(s);
   s =b64_sha1(s);
   alert(s);
}
</SCRIPT>
</HEAD>

<BODY>
<FORM Action="biz.xxx">
<INPUT TYPE="password" NAME="A">
<input type=button value="전송" onClick=AS(this.form.A.value)></P>
</FORM>
</BODY>
</HTML>

이 홈페이지소스에는 sha-1 알고리즘이 구현된 자바스크립트를 포함하였다.


2. 사용자가 A쇼핑몰에 회원으로 신규가입하였다면 해쉬된 패스워드를 DB에 저장하고
   정당한 회원인지 확인하는 로직을 다음과 같이 구현한다.

 

//클라이언트에서 전송된 해쉬된 패스워드
String passwordFromClient = "2yXy/BTNLSseevMHJB9Uj7A8MSo=";

 

//DB에 저장된 패스워드
String passwordFromDB= "2yXy/BTNLSseevMHJB9Uj7A8MSo=";

 

//물론 String 값이 동일한지 비교해도 무방하지만 다음의 비교 로직으로 수행하는것이 보다 안전

byte[] bytePasswordFromClient =  Base64.decodepasswordFromClient);
byte[] bytePasswordFromDB =  Base64.decodepasswordFromDB);

boolean flag = true;

for(int i=0; i < bytePasswordFromClient.length; i++){

    if(bytePasswordFromClient.length!=bytePasswordFromDB.length){
 
        flag = false;
 break;
    }
  
     if(bytePasswordFromClient[i]!=bytePasswordFromDB[i]){

        flag = false;
 break;

     }
}

 

해쉬 알고리즘을 이용하여 패스워드를 암호화를 하게되면 사용자 이외의 누구도 실제 패스워드를
알 수 없다는 것이 보안상의 큰 장점이 된다.
단, 패스워드를 사용자만 알 수 있기 때문에 사용자가 패스워드를 잃어버렸을 경우 본인확인
과정을 거쳐 패스워드를 초기화(재등록)해주는 프로세스를 만들어 주는 친절이 필요하다.


스크랩:http://blog.paran.com/blog/detail/postBoard.kth?blogDataId=28216007&pmcId=javacipher&totalCount=13&preViewPage=0&ajaxPage=1&preFBlogId=35385570&preLBlogId=27788506&pageStyle=null&myCateId=0&yearMonth=null&rDay=null&style=Board&p_eye=

posted by 제스트
:
개발관련/암호화 2009. 12. 31. 15:35

해쉬의 기능이 메시지의 변조 유무룰 확인할 수 있다고 이야기한 바 있다.
문제는 어떤 경로된 원본 데이터와 알고리즘을 알게되면 해쉬값을 만들어 낼 수 있다는
단점이 있다. 그래서 특정 KEY를 해쉬를 과정에서 사용하여 원본을 안다고 하더라도
해쉬값을 유추할 수 없도록 하는 기법을 메시지 인증 코드(MAC, Message Authentication Code)라고 한다.
MAC은 해쉬 알고리즘을 이용할 수 도 있고 암호화 알고리즘을 이용하여 만들 수 있지만 원본 데이터의
무결성을 확인할 수 있는 메시지 축약값이 나온다는 점에서는 해쉬와 동일한다.
특별히 해쉬알고리즘을 이용한 MAC을 HMAC이라고 부른다. HMAC은 매우 자바에서 제공하는 API를 이용하여
매우 쉽게 만들 수 있다.

 

package myBlog;

import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import org.bouncycastle.util.encoders.Base64;

...
//HMAC에 사용할 KEY 
String key = "ABCDEFG";

//해쉬할 데이터
 String data = "12345678901234567890123456789012345678901234567890";
   
//키를 세팅하고 MD5 해쉬알고리즘을 이용한 HMAC을 사용할 것임을 정한다.
SecretKeySpec spec = new SecretKeySpec(key.getBytes(), "hmacMd5");
Mac mac = Mac.getInstance("hmacMd5");
mac.init(spec);
  
byte[] res =mac.doFinal(data.getBytes());

System.out.println(res.length);
System.out.println(new String(Base64.encode(res)));

 

HMAC은 기본적으로 해쉬알고리즘을 사용하기 때문에 결과의 길이는 MD5의 결과값 즉 16바이트가 출력된다.

 

이를 OPENJCE API로 구현하면 다음과 같다.

 

import org.bouncycastle.crypto.digests.MD5Digest;
import org.bouncycastle.crypto.macs.HMac;
import org.bouncycastle.crypto.params.KeyParameter;

 

...

 

 

HMac hmac = new HMac(new MD5Digest());
byte[] res2 =new byte[new MD5Digest().getDigestSize()];
hmac.init(new KeyParameter(key.getBytes()));
hmac.update(data.getBytes(), 0, data.getBytes().length);
 
hmac.doFinal(res2,0);
System.out.println(new String(Base64.encode(res2)));

스크랩:
http://blog.paran.com/blog/detail/postBoard.kth?blogDataId=27934278&pmcId=javacipher&totalCount=13&preViewPage=0&ajaxPage=1&preFBlogId=35385570&preLBlogId=27788506&pageStyle=null&myCateId=0&yearMonth=null&rDay=null&style=Board&p_eye=

posted by 제스트
:
개발관련/암호화 2009. 12. 31. 15:34

해쉬 알고리즘으로 가장 많이 사용하는 SHA-1 알고리즘을 중심으로 살펴보면 보면

 

먼저 JDK에서 제공하는 MessageDigest Class를 이용하면 아래와 같이 매우 간단하게 구현할 수 있다. 

 

import java.security.MessageDigest;

import org.bouncycastle.util.encoders.Base64;

...

 

String s1 = "ABCDEFG";
String s2 = "12345678901234567890123456789012345678901234567890";

 

MessageDigest digest = MessageDigest.getInstance("Sha1");
byte[] res1 = digest.digest(s1.getBytes());
byte[] res2 = digest.digest(s2.getBytes());
    
    
System.out.println("결과값크기= "+res1.length+" 결과값= "+new String(Base64.encode(res1));
System.out.println("결과값크기= "+res2.length+" 결과값= "+new String(Base64.encode(res2));

 

7바이트 s1과 50바이트 s2를 각각 해쉬 하였을 때 출력되는 값은 다르지만 그 길이는 SHA-1 알고리즘의 경우

항상 20바이트가 된다.

 

JDK에서 제공하는 해쉬 알고리즘은 SHA1과 MD5과 같은 제한된 알고리즘인데 반하여 OPENCJCE에서는

보다 다양하고 안전한 알고리즘을 제공한다. 이를 이용한 SHA-1 구현은 다음과 같다.

 

import org.bouncycastle.crypto.digests.GeneralDigest;
import org.bouncycastle.crypto.digests.SHA1Digest;
import org.bouncycastle.util.encoders.Base64;

 

...

 

GeneralDigest sha1digest = new SHA1Digest();

//다이제스트 결과로 얻어질 버퍼

byte[] res3 = new byte[sha1digest.getByteLength()];
   
sha1digest.update(s1.getBytes(), 0, s1.getBytes().length);
sha1digest.update(s2.getBytes(), 0, s2.getBytes().length);  
  
sha1digest.doFinal(re3,0);
System.out.println(new String(Base64.encode(res3)));

스크랩 :
http://blog.paran.com/blog/detail/postBoard.kth?blogDataId=27859061&pmcId=javacipher&totalCount=13&preViewPage=0&ajaxPage=1&preFBlogId=35385570&preLBlogId=27788506&pageStyle=null&myCateId=0&yearMonth=null&rDay=null&style=Board&p_eye=


posted by 제스트
: