대칭키 암호화 알고리즘에서 암복호화에 사용되는 KEY가 무엇을 의미하고 각 알고리즘별로
키길이가 다른 것도 확인한 바 있다.
지난번 소스에서 KEY를 예를들어 byte[] KEY= {(byte)0x12 ...}이런식으로 사용하였는데 또다른
방법으로 키를 만들 수 있는 방법은 없을까?
즉 개발자나 사용자가 이해하고 기억하기 쉬운 예를들면 '123456' 같은 숫자나 문자를 KEY로
암호화에 사용할 수는 없는걸까?
이렇게 사용자나 개발자가 쉽게 사용할 수 있는 문숫자로 KEY를 만들어 사용하는 방법을
패스워드기반암호화(PBE: Password based Encrytion)라고 한다.
내부적인 프로세스는 KEY로 사용될 문자를 받아서 해쉬알고리즘을 통해서 필요한 KEY를 얻게 되는데
특정 문자가 항상 동일한 결과가 나오는 것을 방지하기 위하여 개발자가 이과정에서 인위적으로
특정값을 입력하여 데이터를 혼탁(scrambling)하게 만드는 과정이 추가된다. 이 인위적인 특정값을
salt로 하고 몇번 혼탁하게 만들지도 개발자가 결정하게 된다.
자 그러면 이게부터 "abcd1234"라는 특정 문자가 어떻게 대칭키 알고리즘의 KEY로 사용되는지
소스에서 확인해 보자.
import org.bouncycastle.crypto.PBEParametersGenerator;
import org.bouncycastle.crypto.digests.SHA1Digest;
import org.bouncycastle.crypto.generators.PKCS12ParametersGenerator;
import org.bouncycastle.crypto.params.KeyParameter;
import org.bouncycastle.crypto.params.ParametersWithIV;
//KEY로 만들 문숫자열
String password = "abcd1234"
//8바이트 salt
byte[] SALT = {(byte)0xa1,(byte)0xa2,(byte)0xa3,(byte)0xa4,(byte)0xa5,(byte)0xa6,(byte)0xa7,(byte)0xa8};
//회전수
int COUNT=2000;
//PBE Generator와 해쉬알고리즘, 그리고 PKCS#12에서 정의한 프로세스로 키를 만들겠다고 선언
PBEParametersGenerator peg = new PKCS12ParametersGenerator(new SHA1Digest());
byte[] pass = PBEParametersGenerator.PKCS12PasswordToBytes(password.toCharArray());
//혼탁하게 만들고
peg.init(pass, SALT, COUNT);
//128비트 즉 16바이트 키를 만든다.
ParametersWithIV params = (ParametersWithIV) peg.generateDerivedParameters(128, 128);
KeyParameter kParms = (KeyParameter) params.getParameters();
byte[] KEY =kParms.getKey();
이렇게 나온 KEY를 대칭키암호화에 사용한다.
BufferedBlockCipher blockcipher = new PaddedBufferedBlockCipher(new SEEDEngine());
blockcipher.init(true, new KeyParameter(KEY));
...
나머지 소스는 이전 편을 참조하라.
스크랩:http://blog.paran.com/blog/detail/postBoard.kth?blogDataId=31553399&pmcId=javacipher&totalCount=13&preViewPage=0&ajaxPage=1&preFBlogId=35385570&preLBlogId=27788506&pageStyle=null&myCateId=0&yearMonth=null&rDay=null&style=Board&p_eye=
지금부터는 대칭키 암호화에 관련하여 지난번에 소개한 소스에 대한 설명을 하도록 하겠다.
SEED 알고리즘으로 암호화한 샘플에서 맨 먼저 주목해야 할 부분은 키(KEY)부분이다.
byte[] key = {(byte)0x01,(byte)0x02,(byte)0x03,(byte)0x04,(byte)0x05,(byte)0x06,(byte)0x07,(byte)0x08,
(byte)0x09,(byte)0x10,(byte)0x11,(byte)0x12,(byte)0x13,(byte)0x14,(byte)0x15,(byte)0x16};
대칭키 암호화 알고리즘은 암호화에 사용한 키와 복호화에도 동일하게 사용하게 되는데 중요한 것은
키의 길이다.
SEED 알고리즘은 키의 길이를 128비트(16바이트)를 사용한다. 키의 길이가 128비트라는 이야기는 암호화된
키를 찾아내기 위해서는 2의 128승의 키 중에서 하나를 찾는 작업인데 불가능하지는 않지만 오랜 노력과
시간이 필요하다는 것을 의미한다.
과거에 만들어진 DES 알고리즘의 경우 키의 길이가 64비트(8바이트)였다. 전산 환경의 발달은 2의 64승의
연산은 굳이 슈퍼 컴퓨터를 통하지 않더라고 키를 알아내는데 그다지 긴 기간이 필요하지 않기 때문에 현대에
만들어진 대칭키 알고리즘은 128비트 256비트 등 긴 키 길이를 지원한다.
키길이가 길면 길수록 암호화의 속도는 떨어지기 때문에 128비트의 키길이가 현재 수준에서 가장 적정하다고
받아들여지고 있다.
중요 알고리즘별 키길이는 다음과 같다.
- SEED: 128비트
- DES: 64비트
- Blowfish:64비트
- TripleDES(DESede): 192비트
- AES: 128, 192. 256 비트
국내간에는 SEED가 보편적으로 사용되지만 외국기관간 암호화 통신에는 아직도 DES와 TripleDES을 많이 사용하기
때문에 우선 암호화할 알고리즘이 결정되면 거기에 맞는 키길이로 키를 만들어 주어야 한다.
즉 SEED 알고리즘에서는 128비트 이지만 만약 다른 알고리즘으로 암호화한다고 했을 때
위에 정의한 키의 길이는 8바이트로 만들어 주고 다음과 같이 알고리즘을 호출해 주어야 한다.
//DES시 8바이트 키설정 및 알고리즘 선언
byte[] key = {(byte)0x01,..};
...
PaddedBufferedBlockCipher blockcipher = new PaddedBufferedBlockCipher(new DESEngine());
//TripleDES시 24바이트 키설정 및 알고리즘 선언
byte[] key = {(byte)0x01,..};
...
PaddedBufferedBlockCipher blockcipher = new PaddedBufferedBlockCipher(new DESedeEngine());
//AES시 16 또는 24 또는 32 바이트 키설정 및 알고리즘 선언
byte[] key = {(byte)0x01,..};
...
PaddedBufferedBlockCipher blockcipher = new PaddedBufferedBlockCipher(new AESEngine());
그 이후에 나머지 소스는 동일하다.
스크랩:http://blog.paran.com/blog/detail/postBoard.kth?blogDataId=28779104&pmcId=javacipher&totalCount=13&preViewPage=0&ajaxPage=1&preFBlogId=35385570&preLBlogId=27788506&pageStyle=null&myCateId=0&yearMonth=null&rDay=null&style=Board&p_eye=
그동안 base64, 해쉬 알고리즘 및 활용에 대해서 알아 보았다.
지금부터 본격적으로 암호화에 대한 이야기를 하고자 한다.
암호화는 크게
1) KEY 없는 암호화: 단 이 경우 암호화만 가능하고 복호화는 불가능하다.
2) 하나의 KEY로 암호화 : 하나의 KEY로 암호화된 데이터는 바로 그 키로 복호화된다.
3) 두개의 KEY로 암호화 : KEY가 두개다. 즉 KEY1으로 암호화된 데이터는 KEY2로만 복호화된다.
대칭키 암호화는 2)에 해당된다. 즉 하나의 KEY로만 암복호화가 가능하다.
대칭키 암호화 알고리즘은 보안의 세계에서 가장 보편적으로 사용하는 기법이다.
대칭키 암호화 알고리즘으로 잘 알려진 것들은 DES(Triple DES), AES, Blowfish, RC4 등이 있고
국내에서는 SEED를 민간기관 표준 알고리즘으로 사용하고 있다. 특수한 경우를 제외하고는 각 암호화 알고리즘은
공개되어 있으며 누구나 표준에 따라 구현할 수 있다.
그 동안 자바로 암호화를 구현할 경우 국내 표준 알고리즘이 제외되었기 때문에 구현에 어려움이 있었으나
최근에 SEED가 국제표준화되면서 OPEN 소스에서도 이를 지원하고 있다.
일단 기본적인 암호화 지식을 무시고하고 아래의 소스부터 보자
import org.bouncycastle.crypto.engines.SEEDEngine;
import org.bouncycastle.crypto.paddings.PaddedBufferedBlockCipher;
import org.bouncycastle.crypto.params.KeyParameter;
import org.bouncycastle.util.encoders.Base64;
(중략)
//암호화에 사용될 키
byte[] key = {(byte)0x01,(byte)0x02,(byte)0x03,(byte)0x04,(byte)0x05,(byte)0x06,(byte)0x07,(byte)0x08,
(byte)0x09,(byte)0x10,(byte)0x11,(byte)0x12,(byte)0x13,(byte)0x14,(byte)0x15,(byte)0x16};
//암호화할 데이터
byte[] data = "12345대한민국".getBytes();
//SEED로 암호화할 것을 선언
PaddedBufferedBlockCipher blockcipher = new PaddedBufferedBlockCipher(new SEEDEngine());
//초기화 및 키 파라메터 생성 true는 암호화한다는 의미 false인 경우 복호화
blockcipher.init(true, new KeyParameter(key));
//암호화 프로세스 추가
int len =0;
byte[] tmp = new byte[blockcipher.getOutputSize(data.length)];
len =blockcipher.processBytes(data, 0, data.length, tmp, 0);
try {
len+=blockcipher.doFinal(tmp, len);
} catch (Exception e) {
throw new Exception("암호화 오류가 발생하였습니다.올바른 키로 암호화하였는지 확인하십시오");
}
//암호화된 결과를 담을 버퍼
byte[] out = new byte[len];
System.arraycopy(tmp, 0, out, 0, len);
System.out.println("암호화된 데이터의 길이 ="+out.length);
System.out.println(new String(Base64.encode(out)));
}
//복호화 프로세스 시작
blockcipher.init(false, new KeyParameter(key));
int len2 =0;
byte[] tmp2 = new byte[blockcipher.getOutputSize(out.length)];
len =blockcipher.processBytes(out, 0, out.length, tmp2, 0);
try {
len2+=blockcipher.doFinal(tmp2, len2);
} catch (Exception e) {
throw new Exception("복호화 오류가 발생하였습니다.올바른 키로 복호화하였는지 확인하십시오");
}
//복호화된 데이터를 담을 버퍼
byte[] out2= new byte[len2];
System.arraycopy(tmp2, 0, out2, 0, len2);
System.out.println("복호화된 데이터의 길이 ="+out2.length);
System.out.println(new String(out2));
이상의 소스를 잘 정리하면 SEED 알고리즘을 이용한 암복호화 함수가 완성될 것이다.
이에 대한 부가 설명은 다음편에 계속하겠다.
스크랩:http://blog.paran.com/blog/detail/postBoard.kth?blogDataId=28578038&pmcId=javacipher&totalCount=13&preViewPage=0&ajaxPage=1&preFBlogId=35385570&preLBlogId=27788506&pageStyle=null&myCateId=0&yearMonth=null&rDay=null&style=Board&p_eye=