CryptoEncrypter.java
------------------------------------------------------------------------------
------------------------------------------------------------------------------


import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.MessageDigest;
import java.security.SecureRandom;
import java.util.Arrays;
import java.util.Base64;
import org.json.JSONObject;

public class CryptoEncryptor {

    public static String encryptString(String plainText, String secretKey) throws Exception {
        // Use JSON-style quoting to match PHP json_encode($value)
        String quotedPlainText = JSONObject.quote(plainText);

        byte[] salt = new byte[8];
        new SecureRandom().nextBytes(salt);

        byte[] keyIv = evpBytesToKey(secretKey.getBytes("UTF-8"), salt);
        keyIv = Arrays.copyOf(keyIv, 48); // 32 bytes key + 16 bytes IV

        byte[] key = Arrays.copyOfRange(keyIv, 0, 32);
        byte[] iv = Arrays.copyOfRange(keyIv, 32, 48);

        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        SecretKeySpec keySpec = new SecretKeySpec(key, "AES");
        IvParameterSpec ivSpec = new IvParameterSpec(iv);
        cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec);
        byte[] encrypted = cipher.doFinal(quotedPlainText.getBytes("UTF-8"));

        JSONObject output = new JSONObject();
        output.put("ct", Base64.getEncoder().encodeToString(encrypted));
        output.put("iv", byteArrayToHex(iv));
        output.put("s", byteArrayToHex(salt));

        return Base64.getEncoder().encodeToString(output.toString().getBytes("UTF-8"));
    }

    private static byte[] evpBytesToKey(byte[] pass, byte[] salt) throws Exception {
        MessageDigest md = MessageDigest.getInstance("MD5");
        byte[] dx = new byte[0];
        byte[] result = new byte[0];
        while (result.length < 48) {
            byte[] update = new byte[dx.length + pass.length + salt.length];
            System.arraycopy(dx, 0, update, 0, dx.length);
            System.arraycopy(pass, 0, update, dx.length, pass.length);
            System.arraycopy(salt, 0, update, dx.length + pass.length, salt.length);
            dx = md.digest(update);
            byte[] newResult = new byte[result.length + dx.length];
            System.arraycopy(result, 0, newResult, 0, result.length);
            System.arraycopy(dx, 0, newResult, result.length, dx.length);
            result = newResult;
        }
        return Arrays.copyOf(result, 48);
    }

    private static String byteArrayToHex(byte[] bytes) {
        StringBuilder hex = new StringBuilder();
        for (byte b : bytes) {
            hex.append(String.format("%02x", b));
        }
        return hex.toString();
    }
}

------------------------------------------------------------------------------


TestCrypto.java
------------------------------------------------------------------------------
------------------------------------------------------------------------------

public class TestCrypto {
    public static void main(String[] args) throws Exception {
        if (args.length != 3) {
            System.out.println("Usage: java TestCrypto <text> <key> <encrypt|decrypt>");
            System.exit(1);
        }

        String text = args[0];
        String key = args[1];
        String mode = args[2].toLowerCase();

        if (mode.equals("encrypt")) {
            String encrypted = CryptoEncryptor.encryptString(text, key);
            System.out.println("Encrypted Output:\n" + encrypted);
        } else if (mode.equals("decrypt")) {
            String decrypted = CryptoDecryptor.decryptString(text, key);
            System.out.println("Decrypted Output:\n" + decrypted);
        } else {
            System.out.println("Invalid mode. Use 'encrypt' or 'decrypt'.");
        }
    }
}

