AES 암호화 JAVA, PHP 연동하기

AES 암호화 JAVA, PHP 연동하기

publish date
Jun 30, 2020
Tags
php
java
API 연동시 개발언어가 다르게 (한쪽은 PHP, 한쪽은 JAVA) 개발되어있는 응용프로그램 간의 민감한 데이터를 암호화해서 연동해야 하는 일이 있다면 두 언어간에 호환되는 암호화 방식을 찾아 보신 적 있으실텐데요.
 
저도 그런 경우가 종종 있어서 찾아보니 아래 방법으로 암호화 방식을 서로 일치시켜주면 PHP 와 JAVA 로 각각 짜여진 응용프로그램간에도 문제없이 데이터를 암호화/복호화하여 연동하실 수 있습니다.
 
자 그러면 일단 제가 PHP 를 쓰기 때문에 PHP 코드 부터 보시죠~

코드 ( PHP )

// 제가 테스트한 버전은 PHP 5.3.3 버전입니다.
// PHP 버전에 따라 다를 수 있으니 혹시 암호화 결과가 다르다면 버전을 확인해주세요.
// 아마 5.3 이하나 7.0 이상 버전의 PHP 에서는 문제가 될 소지가 있습니다.

$plain_text = '안녕하세요 HelloWorld';
$secret_key = 'fakecodingsecretfakecodingsecret';

function aes_encode($plain_text, $secret_key) {
    // iv 값은 16 바이트로 설정합니다.
    // $ivBytes = chr(0x00).chr(0x00).chr(0x00).chr(0x00).chr(0x00).chr(0x00).chr(0x00).chr(0x00).chr(0x00).chr(0x00).chr(0x00).chr(0x00).chr(0x00).chr(0x00).chr(0x00).chr(0x00);
    $ivBytes = chr(0).chr(0).chr(0).chr(0).chr(0).chr(0).chr(0).chr(0).chr(0).chr(0).chr(0).chr(0).chr(0).chr(0).chr(0).chr(0);
    // $ivBytes = chr(1).chr(2).chr(3).chr(4).chr(1).chr(2).chr(3).chr(4).chr(1).chr(2).chr(3).chr(4).chr(1).chr(2).chr(3).chr(4);
    return base64_encode(openssl_encrypt($plain_text, "AES-256-CBC", $secret_key, true, $ivBytes));

}

function aes_decode($encrypt_text, $secret_key) {
    // iv 값은 16 바이트로 설정합니다.
    // $ivBytes = chr(0x00).chr(0x00).chr(0x00).chr(0x00).chr(0x00).chr(0x00).chr(0x00).chr(0x00).chr(0x00).chr(0x00).chr(0x00).chr(0x00).chr(0x00).chr(0x00).chr(0x00).chr(0x00);
    $ivBytes = chr(0).chr(0).chr(0).chr(0).chr(0).chr(0).chr(0).chr(0).chr(0).chr(0).chr(0).chr(0).chr(0).chr(0).chr(0).chr(0);
    // $ivBytes = chr(1).chr(2).chr(3).chr(4).chr(1).chr(2).chr(3).chr(4).chr(1).chr(2).chr(3).chr(4).chr(1).chr(2).chr(3).chr(4);
    return openssl_decrypt(base64_decode($encrypt_text), "AES-256-CBC", $secret_key, true, $ivBytes);
}

$encrypt_text = aes_encode($plain_text, $secret_key);
$decrypt_text = aes_decode($encrypt_text, $secret_key);

echo "encrypt_text = ".$encrypt_text;

echo '<br>';

echo "decrypt_text = ".$decrypt_text;
 
실행결과
notion image
[PHP] 암호화 / 복호화 테스트 결과
PHP 버전코드를 보았으니 이제 JAVA 코드를 봅시다.

코드 ( JAVA )

// 테스트 용도로 하나의 파일에 모두 작성하였습니다.

import org.apache.commons.codec.binary.Base64;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.spec.AlgorithmParameterSpec;

/**
 * 암호화 클래스
 */
class AES256Util {

    //    public static byte[] ivBytes = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
    public static byte[] ivBytes = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
//    public static byte[] ivBytes = { 1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4 };

    public static String aes_encode(String str, String key) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException {

        byte[] textBytes = str.getBytes(StandardCharsets.UTF_8);
        AlgorithmParameterSpec ivSpec = new IvParameterSpec(ivBytes);
        SecretKeySpec newKey = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), "AES");
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipher.init(Cipher.ENCRYPT_MODE, newKey, ivSpec);

        return Base64.encodeBase64String(cipher.doFinal(textBytes));
    }

    public static String aes_decode(String str, String key) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException {

        byte[] textBytes = Base64.decodeBase64(str);
        //byte[] textBytes = str.getBytes("UTF-8");
        AlgorithmParameterSpec ivSpec = new IvParameterSpec(ivBytes);
        SecretKeySpec newKey = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), "AES");
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipher.init(Cipher.DECRYPT_MODE, newKey, ivSpec);
        return new String(cipher.doFinal(textBytes), StandardCharsets.UTF_8);
    }
}

/**
 * 암호화 테스트 코드
 */
public class TestClass {

    public static final String plain_text = "안녕하세요 HelloWorld";
    public static final String secret_key = "fakecodingsecretfakecodingsecret";

    public static void main(String[] args) {

        try {

            String encrypt_text = AES256Util.aes_encode(plain_text, secret_key);
            String decrypt_text = AES256Util.aes_decode(encrypt_text, secret_key);
            System.out.println(encrypt_text);
            System.out.println(decrypt_text);

        } catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | InvalidAlgorithmParameterException | IllegalBlockSizeException | BadPaddingException e) {
            e.printStackTrace();
        }

    }
}
 
실행결과
[ JAVA ] 암호화 / 복호화 테스트 결과
[ JAVA ] 암호화 / 복호화 테스트 결과
 
 
그리고 암호화 비밀키 ( secret_key ) 값이 16바이트라면 PHP 상에서 openssl_decrypt 의 method ( 암호화 방식 ) 을AES-256-CBC가 아닌 AES-128-CBC로 변경해주셔야 같은 암/복호화 결과가 나옵니다.
 
감사합니다 😀