2012년 2월 16일

AES 암호화



AES 소개
1997년 1월에, 기존의 데이터 암호 표준, 즉 DES를 대체할 보다 강력한 알고리즘을 찾기 위한 공모 작업이 미국 상무부의 한 기관인 표준기술연구소(NIST)에 의해 시작되었다. 새로운 알고리즘이 충족해야 할 규격 요건으로는, 최소 128 비트나 192 비트 또는 256 비트 크기의 키를 지원하는 128 비트 크기의 블록 암호화를 사용한 대칭형 (암호화나 복호화를 하는데 동일한 키가 사용되는) 알고리즘으로서, 전 세계적으로 로열티 없이 사용할 수 있어야 하며, 향후 20년~30년 동안 데이터를 보호하기 위해 충분한 정도의 보안성을 제공할 것이 요구되었다. 또한, 이 알고리즘은 스마트카드 등과 같은 제한된 환경을 포함하여 하드웨어나 소프트웨어로 구현하기 쉬워야 했으며, 다양한 공격 기술에 대해서도 잘 방어할 수 있어야 했다.

전반적인 선정 과정은 대중적 조사와 평가에 완전히 공개되었으며, 이러한 투명성으로 인해 제출된 모든 설계안들에 대해 최적의 분석이 가능하였다. 1998년에 NIST는 미국 안보국을 포함, 세계의 암호화 단체에 의해 기본적인 분석을 받게 될 15개의 AES 후보작을 선정하였다. 여기에 기반을 두고 1999년 8월, NIST는 보다 심도 있는 2차 분석을 받게 될 다음의 5개 알고리즘을 선정하였다.


  • MARS: IBM 연구소 제출 
  • RC6: RSA Security 제출 
  • Rijndael: 두 명의 벨기에 암호학자 Joan Daemen와 Vincent Rijmen 공동 제출 
  • Serpent: Ross Andersen, Eli Biham 그리고 Lars Knudsen의 공동 제출 
  • Twofish: Counterpane의 존경받는 암호학자 Bruce Schneier를 비롯한 대규모 연구팀 제출 


위의 다섯 개 알고리즘은 모두 ANSI C와 자바 언어를 이용, 하드웨어와 소프트웨어 중심의 시스템 모두에서, 암호화와 복호화 속도 측정, 키와 알고리즘 설정 시간, 다양한 공격에 대한 저항성 등과 같은 심도 있는 시험을 거쳤다. 그 후, 이들 알고리즘은 새로운 암호화 체계를 깨보고자 자원하는 일부 팀을 포함 세계적인 암호화 단체들에 의해 다시 한번, 자세한 분석이 이루어졌다. 그 결과, 2000년 10월 2일에 NIST는 Rijndael를 표준안으로 최종 선정하였다. 2001년 12월 6일, 미 상무부 장관은 민감하지만 비밀로 분류되지 않은 모든 문서들에 AES로서 Rijndael을 사용할 것을 규정하는 연방 정보처리 표준, 즉 FIPS 197을 공식 승인하였다.




AES 사용하기

자바에서 AES 알고리즘을 적용하여 중요한 데이터를 암호화하고 복호화하는 것은 아주 쉬운 일이다.

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Hex;
import org.junit.Test;

public class AESTest {

  private static String sKeyString = "" ;
  private static String message= "This is just an example";

  @Test
  public void testAESEncode() throws Exception {

    // 1. 128 비트 비밀키 생성
    KeyGenerator kgen = KeyGenerator.getInstance("AES");
    kgen.init(128);
    SecretKey skey = kgen.generateKey();

    // 2. 비밀 키를 이렇게 저장하여 사용하면 암호화/복호화가 편해진다.
    sKeyString = Hex.encodeHexString(skey.getEncoded());

    // 3. 암호화 수행
    SecretKeySpec skeySpec = new SecretKeySpec(skey.getEncoded(), "AES");
    Cipher cipher = Cipher.getInstance("AES");
    cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
    byte[] encrypted = cipher.doFinal(message.getBytes());

    System.out.println("encrypted string: " + Hex.encodeHexString(encrypted));

    // 4. 복호화 수행
    cipher.init(Cipher.DECRYPT_MODE, skeySpec);
    byte[] original = cipher.doFinal(encrypted);
    String originalString = new String(original);
    System.out.println("Original string: " + originalString + " " + Hex.encodeHexString(original));

  }
}

예제와 같이 비밀키를 문자로 변환하여 저장해놓고 사용하면 웹 응용프로그램에서 개인정보를 편리하게 암호화하고 복호화 할 수 있다.

암호화와 복호화를 분리한 예제
package architecture.common;

import java.security.SecureRandom;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;

import org.apache.commons.codec.binary.Hex;
import org.junit.Test;


public class AESTest {

private static String encString = "" ;
 
 @Test 
 public void testASEEncodeWithKey() throws Exception {
  
  String password = "1234";
  String username = "원문";
  byte[] seedB = password.getBytes();
  SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");
  sr.setSeed(seedB);  
  KeyGenerator kgen = KeyGenerator.getInstance("AES");
  kgen.init(128, sr); // 192 and 256 bits may not be available  
  // Generate the secret key specs.
  SecretKey skey = kgen.generateKey();
  String keyString = Hex.encodeHexString(skey.getEncoded());
  SecretKeySpec skeySpec = new SecretKeySpec(skey.getEncoded(), "AES");   
  Cipher cipher = Cipher.getInstance("AES");
  cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
     byte[] encrypted =  cipher.doFinal(username.getBytes());
     
     encString =  Hex.encodeHexString(encrypted);
     
     System.out.println("encrypted string: [" + keyString + "] " + encString );
 }
 
 @Test 
 public void testASEDecodeWithKey() throws Exception {
  String password = "1234";
  byte[] seedB = password.getBytes();
  SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");
  sr.setSeed(seedB);
  
  KeyGenerator kgen = KeyGenerator.getInstance("AES");
  kgen.init(128, sr); // 192 and 256 bits may not be available
  
  // Generate the secret key specs.
  SecretKey skey = kgen.generateKey();
  String keyString = Hex.encodeHexString(skey.getEncoded());
  SecretKeySpec skeySpec = new SecretKeySpec(skey.getEncoded(), "AES"); 
  
  Cipher cipher = Cipher.getInstance("AES");
  cipher.init(Cipher.DECRYPT_MODE, skeySpec);
     byte[] decrypted =  cipher.doFinal(Hex.decodeHex(encString.toCharArray()));
     
     System.out.println("decrypted string: [" + keyString + "] " + new String(decrypted));
 }
 
 
 
}
참고자료
암호이용 안내서 (KISA 안내 해설 제 2010-23호)
http://www.terms.co.kr/AES.htm
AES 알고리즘 애니메이션 http://www.formaestudio.com/rijndaelinspector/

댓글 1개: