[JAVA] AES-256 암호화

John·2022년 4월 30일
1

개발 메모🌷

목록 보기
2/13
post-thumbnail

프로젝트 진행 중 암/복호화에 대한 개발을 맡게 됐습니다.

  1. Client가 Request 전송
  2. Native에서 Request 암호화 후 앱 서버로 전송
  3. 앱 서버에서 Request 복호화 후 플랫폼 서버로 전송
  4. 플랫폼 서버에서 앱 서버로 Response 전송
  5. 앱 서버에서 Response 암호화 후 Native로 전송
  6. Native에서 복호화 후 Client에게 Response 전송

저는 앱 서버 개발을 담당하고 있아 복호화된 Request값을 가지고 플랫폼 서버와 통신 후 전달받은 Response값을 암호화해서 Native에 전달하는 작업을 진행해야 합니다.

관련해서 미리 공부하기 위해 적는 글입니다.


AES

AES 정의

AES는 암호화 및 복호화 시 동일한 키를 사용하는 대칭키를 쓰는 블록 암호화 방식입니다.

높은 안정성과 빠른 속도로 전세계적으로 사용되지만, 대칭키를 사용 하기 때문에 키가 유출되는 경우 암호화의 의미가 없어진다는 단점을 가지고 있습니다.


KEY

SECRET KEY

키의 길이에 따라서 AES-128(16bit), AES-192(24bit), AES-256(32bit) 나눠집니다.

Block Cipher

Block Cipher Mode는 CBC 방식을 사용하며, CBC는 블록을 XOR연산을 통해 이전 암호문과 연산을 수행합니다.

첫 번째 암호문에 대해서는 이전 블록이 없기 때문에 이를 위해 IV(initialization vector)를 이용합니다.

여기서 AES는 256비트(32바이트) 단위로 암호화하기 때문에 IV의 크기도 32바이트 크기가 필요합니다.

따라서 매번 다른 IV를 생성하면 같은 평문이라도 다른 암호문을 생성할 수 있습니다.

Padding

비트보다 작은 블록이 생길 경우 부족한 부분을 특정 값으로 채워야합니다.
이러한 작업을 패딩이라고 부르며, 대표적으로 PKCS5, PCKS7 방식이 있습니다.


코드

public class AES256 {

    /* PKCS#5와 PKCS#7 */
    public static final String PADDING = "AES/CBC/PKCS5Padding";

    /* 256비트(32바이트)의 키 */
    private static final String KEY = "aes256encrypt123aes256encrypt123";

    /* initialization vector */
    private static byte[] getIv() {
        return new byte[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
    }

    public static String encrypt(String plainText) throws Exception {
    
        /* 32byte IV initialization */
        byte[] iv = getIv();
        /* KEY String -> byte */
        byte[] keyData = KEY.getBytes();

        /* keyData를 key로 지정, AES algorithm사용 */
        SecretKey secureKey = new SecretKeySpec(keyData, "AES");

        /* CBC PKCS5Padding 방식 사용 */
        Cipher cipher = Cipher.getInstance(PADDING);
        cipher.init(Cipher.ENCRYPT_MODE, secureKey, new IvParameterSpec(iv));

        /* 암호화 */
        byte[] encrypted = cipher.doFinal(plainText.getBytes("UTF-8"));
        return Base64.getEncoder().encodeToString(encrypted);
    }

    public static String decrypt(String cipherText) throws Exception {
    
    	// IOS url-encode 대응
        cipherText = cipherText.replace(" ", "+");
    
        /* 32byte IV initialization */
        byte[] iv = getIv();
        /* KEY String -> byte */
        byte[] keyData = KEY.getBytes();

        /* keyData를 key로 지정, AES algorithm사용 */
        SecretKey secureKey = new SecretKeySpec(keyData, "AES");

        /* CBC PKCS5Padding 방식 사용 */
        Cipher cipher = Cipher.getInstance(PADDING);
        cipher.init(Cipher.DECRYPT_MODE, secureKey, new IvParameterSpec(iv));

        /* 복호화 */
        byte[] decodedBytes = Base64.getDecoder().decode(cipherText.getBytes());
        byte[] decrypted = cipher.doFinal(decodedBytes);

        return new String(decrypted, "UTF-8");
    }

}

테스트


끄적끄적

  1. 실제 프로젝트에서 적용할 때 Key는 properties에서 관리해야 할 것 같다.
  2. 요청값과 응답값에 대해 암/복호화된 값을 확인하기 위해 공통 로그 수정이 필요할 것 같다.

참고
[JAVA] AES-256 암호화 하기
[JAVA] 자바 AES 암호화 하기 (AES-128, AES-192, AES-256)

profile
기록을 습관으로

0개의 댓글