모드와 패딩이 명시되지 않은 AES Cipher 변환

AES 암호화에서 모드와 패딩을 명시해야 하는 이유

설명

Java와 Kotlin에서 Cipher.getInstance("AES")처럼 알고리즘 이름만 지정하면 모드와 패딩 선택이 JCA 공급자 기본값에 맡겨집니다. Oracle JDK 25 문서에 따르면 SunJCE와 SunPKCS11은 여러 대칭키 암호에서 모드와 패딩을 생략할 때 ECB와 PKCS5Padding을 기본값으로 사용하며, SunJCE에서 AES는 AES/ECB/PKCS5Padding과 동일합니다. ECB는 동일한 평문 블록을 동일한 암호문 블록으로 만들기 때문에 반복되는 데이터의 구조와 패턴을 노출하고, 무결성이나 인증을 제공하지 않습니다. 다른 공급자는 기본값이 다를 수 있으므로 기본값 의존은 보안 요구사항과 호환성을 모두 불명확하게 만듭니다.

잠재적 영향

  • 반복되는 평문 패턴이 암호문에 노출되어 데이터 구조나 내용을 추론할 수 있습니다.
  • 인증 기능이 없는 모드를 기본값으로 사용하면 암호문 변조를 탐지하지 못할 수 있습니다.
  • JCA 공급자나 배포 환경 변경 시 암호화 결과가 달라져 복호화 실패 또는 예기치 않은 보안 약화가 발생할 수 있습니다.

해결 방법

  • 알고리즘, 모드, 패딩을 모두 명시하세요.
  • 기밀성과 무결성이 필요하면 검토된 AEAD 모드인 AES/GCM/NoPadding을 우선 사용하세요.
  • GCM에서는 같은 키로 암호화할 때마다 고유한 96비트 nonce를 사용하고 절대 재사용하지 마세요. 무작위 nonce를 사용한다면 SecureRandom으로 12바이트를 생성하고, 복호화에 사용할 수 있도록 암호문과 함께 저장하거나 전송하세요. nonce 자체는 비밀 값이 아닙니다.
  • 기존 ECB 암호문과 호환해야 한다면 신규 암호화와 분리된 마이그레이션 계획을 수립하세요.

예시

변경 전

java
import javax.crypto.Cipher;

Cipher cipher = Cipher.getInstance("AES");

변경 후

key는 별도로 안전하게 생성·관리하는 AES SecretKey입니다. 다음은 암호 초기화 발췌이며, 암호문 저장과 복호화 오류 처리는 생략했습니다.

java
import java.security.SecureRandom;
import javax.crypto.Cipher;
import javax.crypto.spec.GCMParameterSpec;

byte[] nonce = new byte[12];
new SecureRandom().nextBytes(nonce);

Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
cipher.init(Cipher.ENCRYPT_MODE, key, new GCMParameterSpec(128, nonce));

설명:

  • 변경 전: 모드와 패딩이 공급자 기본값에 맡겨져 ECB 같은 안전하지 않은 구성이 선택될 수 있습니다.
  • 변경 후: 인증된 GCM 모드와 96비트 nonce를 명시합니다. 같은 키로 수행하는 다음 암호화에서는 새로운 nonce를 사용해야 하며, 복호화 측에는 해당 nonce를 암호문과 함께 전달해야 합니다.

Kotlin에서도 동일한 javax.crypto.Cipher API를 사용하므로 같은 원칙을 적용합니다.

참조