AES
대칭키 암호화 알고리즘
CBC (Ciper Block Chanining) Mode
블록 암호화 알고리즘에서 데이터의 보안성을 높이기 위해 사용되는 운영모드 중 하나로
블록 암호화 운영 모드 중 보안성이 제일 높은 암호화 방법이다.
CBC 주요 특징은 key 암호화 뿐만 아니라 초기화 벡터(IV) 라는 무작위 값과 XOR 연산을 수행해야 한다.
암호문이 블록의 배수가 되기 때문에 입력되는 평문 데이터가 블록 크기와 맞지 않으면 Padding(패딩)을 추가해서 처리해야 한다.
일반적으로 PKCS5Padding을 사용해 평문의 길이를 블록 크기의 배수로 맞춰준다.
사용 코드
아래 코드는 AES CBC 모드를 사용하여 데이터를 암호화하고 복호화 하는 코드를 작성해두었다.
Bearer 토큰을 통해 동적으로 키와 IV 생성을 하도록해 보안성을 높였다.
makeKey : 32바이트 키 생성
makeIvKey : 16바이트 IV 생성
extractAccessToken : Bearer 토큰 추출
cbcEncrypt : AES CBC 모드로 암호화
cbcDecrypt : AES CBC 모드로 복호화
@Component
public class EncryptionUtils {
private static final String ALGORITHM = "AES";
private static final String CBC_ALGORITHM = "AES/CBC/PKCS5Padding";
//ASE256 key는 32byte
private static final String KEY = "아무_문자로_32바이트_만들기";
// 32바이트 추출을 위한 키 길이 조절
private static String makeKey(String longWord) throws Exception {
if (longWord == null) return KEY;
if (longWord.length() < 32) {
throw new Exception("longword size is short size");
}
return longWord.substring(longWord.length() - 32);
}
// 16바이트 추출을 위한 키 길이 조절
private static String makeIvKey(String longWord) throws Exception {
longWord = extractAccessToken(longWord);
if (longWord == null) return KEY.substring(0, 16);
if (longWord.length() < 16) {
throw new Exception("longword size is short size");
}
return longWord.substring(0, 16);
}
// "Bearer " 문자열 이후 부분만 반환
public static String extractAccessToken(String authHeader) {
// "Bearer " 문자열이 존재하고, 이후에 토큰 값이 존재하는지 확인
if (authHeader != null && authHeader.startsWith("Bearer ")) {
return authHeader.substring(7); // "Bearer " 문자열 이후 부분만 반환
} else {
// 예외 처리 또는 기본 값 반환
return null;
}
}
// 암호화
public static String cbcEncrypt(String data, String customKey) throws Exception {
if (ObjectUtils.isEmpty(data)) {
return null;
}
// AES 키 생성
Key key = new SecretKeySpec(makeKey(customKey).getBytes(), ALGORITHM);
// IV (Initialization Vector) 생성 (16byte)
IvParameterSpec ivParameterSpec = new IvParameterSpec(makeIvKey(customKey).getBytes());
Cipher cipher = Cipher.getInstance(CBC_ALGORITHM);
cipher.init(Cipher.ENCRYPT_MODE, key, ivParameterSpec);
// 암호화
byte[] encryptedData = cipher.doFinal(data.getBytes()); // StandardCharsets.UTF_8
return Base64.encodeBase64String(encryptedData);
}
// 복호화
public static String cbcDecrypt(String data, String customKey) throws Exception {
data = JsonParser.parseString(data).getAsJsonObject().get("enc").getAsString();
if (ObjectUtils.isEmpty(data)) {
return null;
}
// AES 키 생성
Key key = new SecretKeySpec(makeKey(customKey).getBytes(), ALGORITHM);
// IV (Initialization Vector) 생성
IvParameterSpec ivParameterSpec = new IvParameterSpec(makeIvKey(customKey).getBytes());
Cipher cipher = Cipher.getInstance(CBC_ALGORITHM);
cipher.init(Cipher.DECRYPT_MODE, key, ivParameterSpec);
// 복호화
byte[] decryptedData = Base64.decodeBase64(data);
decryptedData = cipher.doFinal(decryptedData);
return new String(decryptedData); // StandardCharsets.UTF_8
}
}
반응형
'백엔드 > Spring' 카테고리의 다른 글
[Spring] MongoDB 조회 - Stream, Aggregation 비교 (0) | 2024.11.04 |
---|---|
[Spring] mongodb, mongodb-reactive Dependency 차이 (0) | 2024.10.31 |
[Spring] 스프링 AOP 포인트컷 (0) | 2024.05.21 |
[Spring] Spring AOP 구현 예제 (0) | 2024.05.17 |
[Spring] AOP 개념 및 용어 정리 (0) | 2024.05.13 |