본문 바로가기

SPRING

SPRING으로 AES CBC, KISA_SEED_CBC 를 활용한 암호화

사용자 CI 나 주민번호 및 핸드폰 번호와 같은 개인정보는 DB에 저장할 때 뿐만아니라 조회되는 데이터도 암호화되어 보여져야 한다. 이를 위해 JAVA의 AES CBC 와 KISA_SEED_CBC를 활용하여 DB에 들어갈 데이터는 AES로 암호화하고 외부로 보여지는 데이터는 KISA_SEED_CBC로 암호화하여 보여지도록 해보자

 

외부 -> DB

BASE64(SEED128 CBC(평문)) 으로 암호화된 데이터를 SEED128 CBC로 복호화하고

복호화된 데이터를 AES로 암호화하여 DB에 저장

DB -> 외부

AES로 암호화된 DB의 데이터를 AES/CBC/PKCS5Padding 로 복호화하고

복호화된 데이터를 SEED128 CBC로 암호화여 외부에 노출

 

 

 

활용 스펙 및 기술 : 

Spring boot

JAVA 11

AES

Base64

KISA_SEED_CBC

 

 

 

KISA SEED CBC - Encrypt

KISA SEED 암호화 알고리즘 적용을 위해 https://seed.kisa.or.kr/kisa/Board/17/detailView.do 에서 사용하고자 하는 언어 및 운영모드에 해당하는 파일을 다운받자

나는 KISA_SEED_CBC.java 파일을 프로젝트에 import 해주었다.

 

    public String encrypt(String masterKey, String msg) throws Exception {
        try {
            byte[] sha256 = getSHA256(masterKey);
            byte[] key = Arrays.copyOfRange(sha256, 0, 16);
            byte[] iv = Arrays.copyOfRange(sha256, 16, 32);

            byte[] data = KISA_SEED_CBC.SEED_CBC_Encrypt(key, iv, msg.getBytes(), 0, msg.getBytes().length);
            return Base64.getEncoder().encodeToString(data);
        } catch (Exception e) {
            log.error("SEED_ENCRYPT_ERROR");
            throw new Exception(e);
        }
    }

 

    private byte[] getSHA256(String msg) throws Exception {
        MessageDigest md = MessageDigest.getInstance("SHA-256");
        md.reset();
        return md.digest(msg.getBytes());
    }

임의의 길이 메시지를 256 비트(bits)의 축약된 메시지로 만들어내는 sha-256 해시 알고리즘을 활용하여 master key를 encoding 해준다.

 

 

KISA SEED CBC - Decrypt

    public String decrypt(String masterKey, String base64Str) throws Exception {
        try {
            byte[] sha256 = getSHA256(masterKey);
            byte[] key = Arrays.copyOfRange(sha256, 0, 16);
            byte[] iv = Arrays.copyOfRange(sha256, 16, 32);

            byte[] decode = Base64.getDecoder().decode(base64Str);
            byte[] dec = KISA_SEED_CBC.SEED_CBC_Decrypt(key, iv, decode, 0, decode.length);
            return new String(dec);
        } catch (Exception e) {
            log.error("SEED_DECRYPT_ERROR");
            throw new Exception(e);
        }
    }

 

 

 

JAVA AES CBC - Encrypt

    final private String cryptoDbIv = "나의 IV";

    final private String cryptoDbKey = "나의 key";

암복호화를 위한 key와 초기화벡터(IV) 를 상수로 설정한다

 

    public String encrypt(String msg) throws Exception {
        try {
            return encryptAes(msg, cryptoDbKey, cryptoDbIv);
        } catch (Exception e) {
            log.error("CRYPTO_ENCRYPT_ERROR");
            throw new Exception(e);
        }
    }
    
    
    private String encryptAes(String plainText, String inputKey, String inputIV) throws Exception {
        byte[] IV = DatatypeConverter.parseHexBinary(inputIV);
        
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        SecretKeySpec key = new SecretKeySpec(inputKey.getBytes(), "AES");
        cipher.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(IV));

        byte[] result = cipher.doFinal(plainText.getBytes(StandardCharsets.UTF_8));
        return DatatypeConverter.printHexBinary(result);
    }

암호화된 데이터는 hex로 encoding하여 string으로 리턴된다.

 

 

 

JAVA AES CBC - Decrypt

    public String decrypt(String msg) throws Exception {
        try {
            return decryptAes(msg, cryptoDbKey, cryptoDbIv);
        } catch (Exception e) {
            log.error("CRYPTO_DECRYPT_ERROR");
            throw new Exception(e);
        }
    }
    
    
    private String decryptAes(String text, String inputKey, String inputIV) throws Exception {
        byte[] cipherText = DatatypeConverter.parseHexBinary(text);
        byte[] IV = DatatypeConverter.parseHexBinary(inputIV);

        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        SecretKeySpec key = new SecretKeySpec(inputKey.getBytes(), "AES");
        cipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(IV));

        return new String(cipher.doFinal(cipherText), StandardCharsets.UTF_8);
    }

 

 

 

적용

 

seedUtil의 encrypt 함수를 호출하여 평문을 SEED128 CBC로 암호화 하자

    public String toSEEDCBCEncrypt(String plainText) throws Exception{
        return seedUtil.encrypt(masterkey, plainText);
    }

 

 

위에서 리턴된 SEED128 CBC 암호화 값은 다음과 같이 AES CBC암호화 값으로 디비에 insert 될 것이다

    public String toDb(String input) throws Exception {
        String plainText = seedUtil.decrypt(masterkey, input);
        log.info("toDb plain text : {}", plainText);
        return cryptoDbUtil.encrypt(plainText);
    }

 

 

 

디비에 들어가 있는 암호화 값이 외부에서 조회될 때는 다음과 같이 SEED128 CBC로 암호화 되어 보여진다

이 암호화 값은 encrypt-text api 를 호출해서 받았던 결과값과 동일하다

    public String toExternal(String input) throws Exception {
        String plainText = cryptoDbUtil.decrypt(input);
        log.info("toExternal plain text : {}", plainText);
        return seedUtil.encrypt(masterkey, plainText);
    }

 

 

복호화 될 때 plain text 또한 동일한 부분 log로 확인 가능하다

 

 

 

 

끄읏 -!