정보보호 진흥원에서 제공하는 SEED 암호화를 아래와 같이 쓸 수 있도록 하였다.
- byte배열 <-> String 간 변환을 손쉽게 할 수 있도록 구성
- 16바이트를 맞추기 위해 쓰는 Padding 방식은 PKCS5Padding 을 사용한다.
- CBC 운영모드를 적용한다.
public static void main(String[] args) throws UnsupportedEncodingException
{
PropertiesReader.init();
String password = "010-222-2222";
String key = PropertiesReader.getProperties("public_key");
// Encrypt
byte[] pbCipher = Seedx.Encrypt(key, password, "euc-kr");
// Decrypt
String data = Seedx.Decrypt(key, pbCipher, "euc-kr");
System.out.println(data);
}
// 암호화
public static byte[] Encrypt(final String pbKey, final String plainText, String charset)
{
byte[] byteIV = {
(byte)0x26, (byte)0x8D, (byte)0x66, (byte)0xA7, (byte)0x35, (byte)0xA8, (byte)0x1A, (byte)0x81,
(byte)0x6F, (byte)0xBA, (byte)0xD9, (byte)0xFA, (byte)0x36, (byte)0x16, (byte)0x25, (byte)0x01
};
byte[] pbUserKey = HexUtil.byteLengthPadding(pbKey.getBytes(Charset.forName(charset)), NoRounds);
byte[] pbPlain = HexUtil.addPadding(plainText.getBytes(Charset.forName(charset)), SeedBlockSize);
byte[] pbCipher = new byte[pbPlain.length];
int[] pdwRoundKey =getSeedRoundKey(pbUserKey);
int rt = pbPlain.length / SeedBlockSize;
for (int j = 0; j < rt; j++) {
byte[] sSource = new byte[SeedBlockSize];
byte[] sTarget = new byte[SeedBlockSize];
System.arraycopy(pbPlain, (j * SeedBlockSize), sSource, 0, SeedBlockSize);
// CBC 운영모드
exclusiveOR(sSource, byteIV);
SeedEncrypt(sSource, pdwRoundKey, sTarget);
byteIV = sTarget;
System.arraycopy(sTarget, 0, pbCipher, (j * SeedBlockSize), sTarget.length);
}
// System.out.println("KEY : " + HexUtil.byteArrayToHex(pbUserKey));
// System.out.println("TEXT : " + HexUtil.byteArrayToHex(pbPlain));
// System.out.println("ENC : " + HexUtil.byteArrayToHex(pbCipher));
return pbCipher;
}
public static String Decrypt(String pbKey, byte[] encryptBytes, String charset)
{
byte[] byteIV = {
(byte)0x26, (byte)0x8D, (byte)0x66, (byte)0xA7, (byte)0x35, (byte)0xA8, (byte)0x1A, (byte)0x81,
(byte)0x6F, (byte)0xBA, (byte)0xD9, (byte)0xFA, (byte)0x36, (byte)0x16, (byte)0x25, (byte)0x01
};
byte pbUserKey[] = HexUtil.addPadding(pbKey.getBytes(Charset.forName(charset)), SeedBlockSize);
byte decryptBytes[] = new byte[encryptBytes.length];
int[] pdwRoundKey =getSeedRoundKey(pbUserKey);
int rt = encryptBytes.length / SeedBlockSize;
byte sSource[] = new byte[SeedBlockSize];
byte sTarget[] = new byte[SeedBlockSize];
for (int j = 0; j < rt; j++) {
System.arraycopy(encryptBytes, (j * SeedBlockSize), sSource, 0, SeedBlockSize);
SeedDecrypt(sSource, pdwRoundKey, sTarget);
// CBC 운영모드
exclusiveOR(sTarget, byteIV);
byteIV = sSource;
System.arraycopy(sTarget, 0, decryptBytes, (j * SeedBlockSize), SeedBlockSize);
}
decryptBytes = HexUtil.removePadding(decryptBytes, SeedBlockSize);
return new String(decryptBytes, Charset.forName(charset));
}
/**
* 암/복호화에 사용할 key값을 생성
* @param keyStr - 생성할 key값의 string 값
* @return
* @throws Exception
*/
public static int[] getSeedRoundKey(byte[] keyStr){
int[] seedKey = new int[NoRoundKeys];
SeedRoundKey(seedKey, keyStr);
return seedKey;
}
/**
* CBC 운영모드를 사용하기 위한 XOR 연산 메서드
* value1과 value2를 XOR 연산 후 그 결과를 value1에 담는다.
* 128bit 확정형
* @param value1 - 변수1
* @param value2 - 변수2
*/
private static void exclusiveOR(byte[] value1, byte[] value2)
{
for(int i = 0; i < SeedBlockSize; i++)
{
value1[i] = Integer.valueOf(value1[i] ^ value2[i]).byteValue();
}
}
아래는 HexUtil 클래스 메서드
/**
* 패킷내 정의된 필드의 길이가 남을때 0x00으로 채운다
*
* @param b : 대상 바이트 배열
* @param length : 필드 길이
*/
public static byte[] byteLengthPadding(byte[] b, int length)
{
int size = b.length;
byte[] data = null;
if (size == length)
{
data = b;
}
else if (size < length)
{
data = new byte[length];
System.arraycopy(b, 0, data, 0, size);
for (int i = size; i < length; i++)
{
data[ i] = (byte) 0x00;
}
}
else if (size > length)
{
data = new byte[length];
System.arraycopy(b, 0, data, 0, length);
}
return data;
}
/**
* 패킷내 정의된 필드의 길이가 남을때 패딩개수로 채운다
* PKCSPadding
*
* @param b : 대상 바이트 배열
* @param blockSize : 블럭 길이
*/
public static byte[] addPadding(byte[] source, int blockSize)
{
int paddingCnt = source.length % blockSize;
byte[] paddingResult = null;
if(paddingCnt != 0)
{
paddingResult = new byte[source.length + (blockSize - paddingCnt)];
System.arraycopy(source, 0, paddingResult, 0, source.length);
// 패딩해야 할 갯수 - 1 (마지막을 제외)까지 0x00 값을 추가한다.
int addPaddingCnt = blockSize - paddingCnt;
for(int i=0;i<addPaddingCnt;i++)
{
paddingResult[source.length + i] = (byte)addPaddingCnt;
}
}
else
{
paddingResult = source;
}
return paddingResult;
}
/**
* 패킷내 패딩된 0x00을 제거한다.
* ANSI-X.923-Padding
* @param source
* @param blockSize
* @return
*/
public static byte[] removePadding(byte[] source, int blockSize)
{
byte PADDING_VALUE = 0x00;
byte[] paddingResult = null;
boolean isPadding = false;
// 패딩 된 count를 찾는다.
int lastValue = source[source.length - 1];
if(lastValue < (blockSize - 1)) {
int zeroPaddingCount = lastValue - 1;
for(int i=2;i<(zeroPaddingCount + 2);i++) {
if(source[source.length - i] != PADDING_VALUE) {
isPadding = false;
break;
}
}
isPadding = true;
} else {
// 마지막 값이 block size 보다 클 경우 패딩 된것이 없음.
isPadding = false;
}
if(isPadding) {
paddingResult = new byte[source.length - lastValue];
System.arraycopy(source, 0, paddingResult, 0, paddingResult.length);
} else {
paddingResult = source;
}
return paddingResult;
}
'백엔드기술 > 개발언어' 카테고리의 다른 글
Tika 소개 - 유용한 Parser 라이브러리 (1) | 2012.12.14 |
---|---|
Java Tip static Import (0) | 2012.11.20 |
jackson 라이브러리 (0) | 2012.10.23 |