본문 바로가기

Spring Boot

랜덤한 IV(Initial Vector)를 사용하여 AES256 암호화, 복호화 하기

728x90

안녕하세요 유저인사이트 박태양입니다.

 

프로젝트를 진행하다 보면, 개인정보와 같은 암호화가 필요한 필드들이 있습니다.

 

AES256 관련된 코드를 구글링 해보면 대부분의 블로그에서 IV값을 고정값으로 사용하고 있습니다.

 

이는 권장되지 않는 방식입니다. 저희는 소나큐브를 통해 아래와 같은 메시지를 확인할 수 있었습니다.

 

Use a dynamically-generated, random IV

 

 

왜 문제가 되는것일까요?

 

IV를 고정된 값으로 처리하면, 입력한 값이 동일한 경우 동일한 암호화 결과를 제공합니다.

 

예를들면 "박태양"이라는 문자열을 암호화할때 

1회차 : $2a$12$lYImjNoPVvNn30O

2회차 : $2a$12$lYImjNoPVvNn30O

 

IV를 랜덤한 값으로 처리하면 아래와 같이 결과가 미세하게 달라집니다.

1회차 : $2a$12$lYImjNoPVvNn30O

2회차 : $2a$12$U6HtvOCNeXacSh

 

그런데 만약 암호화 시점에 랜덤하게 생성한 IV를 사용한다면, 복호화 시점에는 어떻게 IV값을 설정해야 하는것일까요?

 

아래는 ChatGPT를 활용하여 생성한 코드입니다.

 

public class AesEncryptionUtil {
    private static final int AES_KEY_SIZE = 256;
    private static final int IV_SIZE = 16; // 128 bits IV for AES
    private static final String AES_ALGORITHM = "AES/CBC/PKCS5PADDING";

    public static String encrypt(String value, String secretKey) throws Exception {
        SecureRandom random = new SecureRandom();
        byte[] iv = new byte[IV_SIZE];
        random.nextBytes(iv);
        IvParameterSpec ivSpec = new IvParameterSpec(iv);

        SecretKeySpec skeySpec = new SecretKeySpec(secretKey.getBytes(), "AES");

        Cipher cipher = Cipher.getInstance(AES_ALGORITHM);
        cipher.init(Cipher.ENCRYPT_MODE, skeySpec, ivSpec);

        byte[] encrypted = cipher.doFinal(value.getBytes());
        byte[] combined = new byte[iv.length + encrypted.length];
        System.arraycopy(iv, 0, combined, 0, iv.length);
        System.arraycopy(encrypted, 0, combined, iv.length, encrypted.length);

        return Base64.getEncoder().encodeToString(combined);
    }

    public static String decrypt(String encryptedValue, String secretKey) throws Exception {
        byte[] combined = Base64.getDecoder().decode(encryptedValue);
        byte[] iv = new byte[IV_SIZE];
        System.arraycopy(combined, 0, iv, 0, IV_SIZE);
        IvParameterSpec ivSpec = new IvParameterSpec(iv);

        SecretKeySpec skeySpec = new SecretKeySpec(secretKey.getBytes(), "AES");

        Cipher cipher = Cipher.getInstance(AES_ALGORITHM);
        cipher.init(Cipher.DECRYPT_MODE, skeySpec, ivSpec);

        byte[] decrypted = cipher.doFinal(combined, IV_SIZE, combined.length - IV_SIZE);
        return new String(decrypted);
    }
}

 

IV의 크기(코드에서는 16자리)를 정해놓고 DB에 저장할때 암호화된 문자열 앞에 IV값을 붙여서 저장합니다.

 

DB에 암호화된 데이터 = 16자리IV + 암호화된 문자열

 

위와 같은 형식을 가지게 되는것입니다.

 

복호화 시점에 앞에서 16자리는 IV로 처리하고, 나머지 값을 복호화하면 됩니다.

 

감사합니다.

 

 

 

 

 

728x90