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;

실행결과

[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 ] 암호화 / 복호화 테스트 결과

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

감사합니다 😀