import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.util.Base64;

public class AES256 {
    /**
     * 암호화 기법 중 AES256 방법을 소개
     * 대표적인 양방향 암호화
     * 대칭키: 암호화, 복호화에 동일한 키가 사용 됨
     * 비대칭키: 암호화, 복호화의 다른 키가 다름
     */

    // 16바이트(128비트) IV(Initialization Vector). CBC 모드에서 첫 블록을 암호화할 때 사용.
    private static final String IV = "1234567890abcdef";
    // 32바이트(256비트) 비밀 키. AES256 암호화/복호화에 사용됩니다.
    private static final String secretKey = "12345678ABCDEFGHabcdefgh12345678";


    /**
     * Cipher 객체를 생성하고 초기화하는 메서드
     *
     * @param cipherMode 암호화(Cipher.ENCRYPT_MODE) 또는 복호화(Cipher.DECRYPT_MODE) 모드 지정
     * @return 초기화된 Cipher 객체
     * @throws Exception Cipher 생성 또는 초기화 중 발생할 수 있는 모든 예외 처리
     */
    public static Cipher createdAES256(int cipherMode) throws Exception {
        // AES 알고리즘, CBC 모드, PKCS5 패딩을 지정하여 Cipher 인스턴스 생성
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");

        // 비밀 키(secretKey)를 UTF-8 바이트 배열로 변환
        byte[] keyBytes = secretKey.getBytes(StandardCharsets.UTF_8);
        // IV(초기화 벡터)를 UTF-8 바이트 배열로 변환하여 IvParameterSpec 객체 생성
        IvParameterSpec ivParameterSpec = new IvParameterSpec(IV.getBytes(StandardCharsets.UTF_8));

        // 키 바이트 배열과 "AES" 알고리즘 이름을 사용하여 SecretKeySpec 객체 생성
        SecretKeySpec secretKeySpec = new SecretKeySpec(keyBytes, "AES");
        // 생성한 Cipher 객체를 지정된 모드(암호화/복호화), 비밀 키, IV로 초기화
        cipher.init(cipherMode, secretKeySpec, ivParameterSpec);

        return cipher;
    }

    /**
     * 평문(plainText)을 AES256으로 암호화하고 Base64로 인코딩합니다.
     *
     * @param plainText 암호화할 평문 문자열
     * @return Base64로 인코딩된 암호문 문자열
     * @throws Exception 암호화 중 발생할 수 있는 모든 예외 처리
     */
    public static String encrypt(String plainText) throws Exception {
        // 암호화 모드로 초기화된 Cipher 객체 가져오기
        Cipher cipher = createdAES256(Cipher.ENCRYPT_MODE);
        // 평문 문자열을 UTF-8 바이트 배열로 변환하여 암호화 실행
        byte[] encryptedBytes = cipher.doFinal(plainText.getBytes(StandardCharsets.UTF_8));
        // 암호화된 이진 데이터를 Base64 인코딩하여 안전한 문자열로 변환 후 반환
        return Base64.getEncoder().encodeToString(encryptedBytes);
    }

    /**
     * Base64로 인코딩된 암호문(encryptedText)을 복호화하여 평문으로 되돌립니다.
     *
     * @param encryptedText 복호화할 Base64 인코딩된 암호문
     * @return 복호화된 평문 문자열
     * @throws Exception 복호화 중 발생할 수 있는 모든 예외 처리 (Base64 디코딩 실패 포함)
     */
    public static String decrypt(String encryptedText) throws Exception {
        // 복호화 모드로 초기화된 Cipher 객체 가져오기
        Cipher cipher = createdAES256(Cipher.DECRYPT_MODE);
        // Base64로 인코딩된 문자열을 이진 바이트 배열로 디코딩
        byte[] encryptedBytes = Base64.getDecoder().decode(encryptedText);
        // 디코딩된 바이트 배열을 복호화 실행
        byte[] decryptedBytes  = cipher.doFinal(encryptedBytes);
        // 복호화된 바이트 배열을 UTF-8 문자열로 변환하여 반환
        return new String(decryptedBytes, StandardCharsets.UTF_8);
    }

    /**
     * 메인 메서드: 암호화 및 복호화 과정을 테스트합니다.
     * @param args 프로그램 인자 (사용되지 않음)
     * @throws Exception 테스트 과정 중 발생할 수 있는 모든 예외 처리
     */
    public static void main(String[] args) throws Exception {
        String plainText = "Hello~~";
        System.out.println("plainText :: " + plainText);
        String encrypted = encrypt(plainText);
        System.out.println("encrtyped :: " + encrypted);
        String decrypted = decrypt(encrypted);
        System.out.println("decrypted :: " + decrypted);
    }
}

+ Recent posts