본문 바로가기
백엔드기술/개발언어

정보보호 진흥원 SEED 암호화/ SEED 알고리즘

by RevFactory 2012. 12. 4.

정보보호 진흥원에서 제공하는 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();
  }
 }
 
 

 

 

 

Seedx.java

 

 

 

아래는 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