요즘 암복호화로 고통을 좀 받고 있어서 자세히 찾아보고 정리하려고 한다.
1. 알고리즘이란?
알고리즘은 데이터를 섞는 규칙(방법)이다.
코드 작성한 부분 중 이 부분이 알고리즘 부분이다.
static final String ALGORITHM = "AES";
static final int KEY_LENGTH = 256;
비유: 금고를 만들 때 다이얼 방식으로 만들지, 지문인식으로 만들지 결정하는 설계도와 같다. 요즘 가장 표준적인 방식이 AES이다.
- AES-128: 키 길이가 16바이트
- AES-256: 키 길이가 32바이트
2. IV(초기화 벡터) 가 왜 필요한가?
만약 IV가 없다면? 동일한 키로 "Hello"라는 단어를 암호화할 때, 결과값이 항상 똑같이 ABCDE 라고 나온다면 ABCDE가 나오면 저건 "Hello" 구나 라고 패턴을 파악할 수 있다. IV를 넣으면 암호화할 때마다 랜덤한 IV를 섞어준다.
3. 나의 암호화 흐름
나의 암호화 코드는 아래 순서로 동작하고 있다.
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.SecureRandom;
import java.util.Base64;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
/**
* AES-256 암호화/복호화 유틸리티 클래스
*/
public class Encrypt {
/**
* 랜덤 AES-256 키 생성
*
* @return Base64로 인코딩된 키
*/
public static String generateKey() throws Exception {
KeyGenerator keyGenerator = KeyGenerator.getInstance(ALGORITHM);
keyGenerator.init(KEY_LENGTH);
SecretKey secretKey = keyGenerator.generateKey();
return Base64.getEncoder().encodeToString(secretKey.getEncoded());
}
/**
* 랜덤 IV(Initialization Vector) 생성
*
* @return 16바이트 IV
*/
private static byte[] generateIV() {
byte[] iv = new byte[IV_LENGTH];
new SecureRandom().nextBytes(iv);
return iv;
}
/**
* 바이트 배열 암호화 (파일용)
*
* @param data 암호화할 바이트 배열
* @param key Base64로 인코딩된 키
* @return 암호화된 바이트 배열 (IV + 암호문)
*/
public static byte[] encryptBytes(byte[] data, String key) throws Exception {
// 키 디코딩
byte[] keyBytes = Base64.getDecoder().decode(key);
SecretKeySpec secretKeySpec = new SecretKeySpec(keyBytes, ALGORITHM);
// IV 생성
byte[] iv = generateIV();
IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);
// 암호화
Cipher cipher = Cipher.getInstance(TRANSFORMATION);
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec);
byte[] encryptedBytes = cipher.doFinal(data);
// IV + 암호문을 합치기
byte[] encryptedWithIv = new byte[IV_LENGTH + encryptedBytes.length];
System.arraycopy(iv, 0, encryptedWithIv, 0, IV_LENGTH);
System.arraycopy(encryptedBytes, 0, encryptedWithIv, IV_LENGTH, encryptedBytes.length);
return encryptedWithIv;
}
/**
* 파일 암호화
*
* @param inputFilePath 암호화할 파일 경로
* @param outputFilePath 암호화된 파일을 저장할 경로
* @param key Base64로 인코딩된 키
*/
/**
* [추가] 인자 없는 encrypt 메서드: 고정 키를 사용함
*/
public static String encryptFile(String plainText) throws Exception {
// 내부적으로 아래의 (String, String) 메서드를 호출
return encrypt(plainText, Base64.getEncoder().encodeToString(FIXED_KEY.getBytes()));
}
public static void encryptFile(String inputFilePath, String outputFilePath, String key) throws Exception {
// 파일 읽기
byte[] fileData = Files.readAllBytes(Paths.get(inputFilePath));
// 암호화
byte[] encryptedData = encryptBytes(fileData, key);
// 암호화된 데이터를 파일로 저장
Files.write(Paths.get(outputFilePath), encryptedData);
System.out.println("File Encrypt Success: " + inputFilePath + " -> " + outputFilePath);
}
}
1. 키(Key) 준비: 32바이트짜리 열쇠를 준비한다.
2. IV 생성: 암호화할 때마다 랜덤한 16바이트 IV를 생성한다.
3. 암호화: 평문 + 키 + IV 를 알고리즘(AES)에 넣고 돌린다.
4. encryptedWithIv 라는 새 바이트 배열을 만들어서, 앞쪽 16바이트에는 IV를, 그 뒤에는 암호화된 데이터를 순서대로 복사한다.
복호화할 때는?
1. 하나로 묶인 데이터에서 앞의 16바이트(IV)를 먼저 떼어낸다.
2. 나머지 암호문을 가져온다.
3. 내가 가진 키와 방금 떼어낸 IV를 이용해 다시 원래 글로 바꾼다.
4. 코드 하나하나 뜯어보기
Cipher cipher = Cipher.getInstance(TRANSFORMATION);
'알고리즘/운영모드/패딩방식' 을 설정하는 설계도 역할
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec);
도구를 암호화모드로 초기화한다. 이때 암호화 키와 IV를 장착한다.
byte[] encryptedBytes = cipher.doFinal(data);
실제 데이터를 암호화 알고리즘에 통과시켜 암호문을 생성한다.
doFinal 은 데이터의 끝을 알리고 암호화 작업을 마무리하는 명령어이다.
byte[] encryptedWithIv = new byte[IV_LENGTH + encryptedBytes.length];
새로운 바이트 배열을 만든다. 크기는 IV 길이 + 암호문 길이로 설정한다. 나중에 복호화할 때 IV가 필요하기 때문에 둘을 한 배열에 담으려는 준비 과정이다.
System.arraycopy(iv, 0, encryptedWithIv, 0, IV_LENGTH);
System.arraycopy(encryptedBytes, 0, encryptedWithIv, IV_LENGTH, encryptedBytes.length);
배열 맨 앞부분(0번 위치)에 IV를 복사해서 넣는다.
IV 바로 뒷부분에 실제 암호문을 이어 붙인다.
5. AES 외의 주요 암복호화 방식
| 방식 구분 | 종류 | 특징 및 용도 |
| 대칭키 | DES/3DES | 과거 표준이었으나 보안 취약점이 발견되어 현재는 거의 쓰지 않거나 AES로 대체되었습니다. |
| ARIA/SEED | 국산 암호 알고리즘입니다. 공공기관이나 국내 금융권 프로젝트에서 보안 가이드를 따를 때 필수로 요구되기도 합니다. | |
| 비대칭키 | RSA | 암호화용 키와 복호화용 키가 다릅니다. 속도는 느리지만 키 전달이 안전해서, 주로 로그인을 하거나 대칭키를 안전하게 주고받을 때 사용합니다. |
'Java' 카테고리의 다른 글
| [java] 통계 시스템 제작 # 01 (0) | 2025.07.09 |
|---|---|
| [Java] thread 생성 방식 - (Runnable + Thread) (1) | 2025.06.17 |
| [java] db에 적재된 디렉토리 경로 수정하기 (3) | 2024.09.26 |
| [java] 서버에서 db2 데이터 이관 (0) | 2024.08.12 |