프로젝트 진행 중 암/복호화에 대한 개발을 맡게 됐습니다.
저는 앱 서버 개발을 담당하고 있아 복호화된 Request값을 가지고 플랫폼 서버와 통신 후 전달받은 Response값을 암호화해서 Native에 전달하는 작업을 진행해야 합니다.
관련해서 미리 공부하기 위해 적는 글입니다.
AES는 암호화 및 복호화 시 동일한 키를 사용하는 대칭키를 쓰는 블록 암호화 방식입니다.
높은 안정성과 빠른 속도로 전세계적으로 사용되지만, 대칭키를 사용 하기 때문에 키가 유출되는 경우 암호화의 의미가 없어진다는 단점을 가지고 있습니다.
키의 길이에 따라서 AES-128(16bit), AES-192(24bit), AES-256(32bit) 나눠집니다.
Block Cipher Mode는 CBC 방식을 사용하며, CBC는 블록을 XOR연산을 통해 이전 암호문과 연산을 수행합니다.
첫 번째 암호문에 대해서는 이전 블록이 없기 때문에 이를 위해 IV(initialization vector)를 이용합니다.
여기서 AES는 256비트(32바이트) 단위로 암호화하기 때문에 IV의 크기도 32바이트 크기가 필요합니다.
따라서 매번 다른 IV를 생성하면 같은 평문이라도 다른 암호문을 생성할 수 있습니다.
비트보다 작은 블록이 생길 경우 부족한 부분을 특정 값으로 채워야합니다.
이러한 작업을 패딩이라고 부르며, 대표적으로 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");
}
}
참고
[JAVA] AES-256 암호화 하기
[JAVA] 자바 AES 암호화 하기 (AES-128, AES-192, AES-256)