You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何实现PHP与Java的AES-256-CBC加密结果一致?

实现与PHP AES-256-CBC加解密兼容的Java代码

问题背景

已有PHP实现的AES-256-CBC加解密逻辑,需要编写对应的Java代码,保证双方加密结果一致、互相可解密。此前尝试的两种Java实现因逻辑不匹配,无法兼容。

PHP代码的核心兼容要点

要实现兼容,必须完全复刻PHP的密钥、IV生成及加解密流程:

  • 密钥生成:对原始密钥字符串执行SHA256哈希,得到64字符的十六进制字符串,取前32个字符的UTF-8字节作为AES-256密钥(PHP的openssl_encrypt会自动截断过长的密钥字符串至算法要求的32字节)
  • IV生成:对原始IV字符串执行SHA256哈希,得到64字符的十六进制字符串,取前16个字符的UTF-8字节作为AES-CBC的IV(长度符合16字节要求)
  • 加密流程:明文 → AES-256-CBC加密(PKCS#7填充)→ 加密结果转base64 → 再次对该base64字符串执行base64编码
  • 解密流程:输入值base64解码 → 得到加密结果的base64字符串 → 解码后执行AES-256-CBC解密 → 得到明文

现有Java实现的问题

  1. 第一种实现使用PBKDF2密钥派生,与PHP直接SHA256哈希的逻辑完全不符,导致密钥不一致
  2. 第一种实现使用全0数组作为IV,未复刻PHP的IV生成逻辑
  3. 第二种实现直接使用原始密钥/IV的字节数组,未做SHA256哈希处理;且使用NoPadding,与PHP默认的PKCS#7填充不兼容
  4. 两种实现均未处理PHP的双重base64编码逻辑

正确的Java实现

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.util.Base64;

public class AESCompatible {
    private static final String RAW_KEY = "myKey"; // 与PHP的$key保持一致
    private static final String RAW_IV = "myIv";   // 与PHP的$iv保持一致
    private static final String AES_ALGORITHM = "AES/CBC/PKCS5Padding";

    // 计算字符串的SHA256哈希,返回十六进制字符串
    private static String sha256Hex(String input) {
        try {
            MessageDigest digest = MessageDigest.getInstance("SHA-256");
            byte[] hashBytes = digest.digest(input.getBytes(StandardCharsets.UTF_8));
            StringBuilder hexBuilder = new StringBuilder();
            for (byte b : hashBytes) {
                String hex = Integer.toHexString(0xFF & b);
                if (hex.length() == 1) {
                    hexBuilder.append('0');
                }
                hexBuilder.append(hex);
            }
            return hexBuilder.toString();
        } catch (Exception e) {
            throw new RuntimeException("SHA256哈希计算失败", e);
        }
    }

    public static String encrypt(String plainText) {
        if (plainText == null) {
            return null;
        }

        try {
            // 生成兼容PHP的密钥
            String keyHex = sha256Hex(RAW_KEY);
            byte[] keyBytes = keyHex.substring(0, 32).getBytes(StandardCharsets.UTF_8);
            SecretKeySpec secretKey = new SecretKeySpec(keyBytes, "AES");

            // 生成兼容PHP的IV
            String ivHex = sha256Hex(RAW_IV);
            byte[] ivBytes = ivHex.substring(0, 16).getBytes(StandardCharsets.UTF_8);
            IvParameterSpec ivSpec = new IvParameterSpec(ivBytes);

            // 初始化加密器
            Cipher cipher = Cipher.getInstance(AES_ALGORITHM);
            cipher.init(Cipher.ENCRYPT_MODE, secretKey, ivSpec);

            // 执行加密,对应PHP openssl_encrypt的base64输出
            byte[] encryptedBytes = cipher.doFinal(plainText.getBytes(StandardCharsets.UTF_8));
            String firstBase64 = Base64.getEncoder().encodeToString(encryptedBytes);

            // 二次base64编码,对应PHP的base64_encode
            return Base64.getEncoder().encodeToString(firstBase64.getBytes(StandardCharsets.UTF_8));
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    public static String decrypt(String encryptedText) {
        if (encryptedText == null) {
            return null;
        }

        try {
            // 解码外层base64,得到PHP openssl_encrypt返回的base64字符串
            byte[] firstDecode = Base64.getDecoder().decode(encryptedText);
            String encryptedBase64 = new String(firstDecode, StandardCharsets.UTF_8);

            // 生成兼容PHP的密钥和IV
            String keyHex = sha256Hex(RAW_KEY);
            byte[] keyBytes = keyHex.substring(0, 32).getBytes(StandardCharsets.UTF_8);
            SecretKeySpec secretKey = new SecretKeySpec(keyBytes, "AES");

            String ivHex = sha256Hex(RAW_IV);
            byte[] ivBytes = ivHex.substring(0, 16).getBytes(StandardCharsets.UTF_8);
            IvParameterSpec ivSpec = new IvParameterSpec(ivBytes);

            // 初始化解密器
            Cipher cipher = Cipher.getInstance(AES_ALGORITHM);
            cipher.init(Cipher.DECRYPT_MODE, secretKey, ivSpec);

            // 解码内层base64并解密
            byte[] encryptedBytes = Base64.getDecoder().decode(encryptedBase64);
            byte[] decryptedBytes = cipher.doFinal(encryptedBytes);

            return new String(decryptedBytes, StandardCharsets.UTF_8);
        } catch (Exception e) {
            e.printStackTrace();
            // 对应PHP中无法base64解码的情况,返回原输入
            return encryptedText;
        }
    }

    // 测试验证
    public static void main(String[] args) {
        String testStr = "Hello AES Compatible!";
        String encrypted = encrypt(testStr);
        System.out.println("加密结果:" + encrypted);
        String decrypted = decrypt(encrypted);
        System.out.println("解密结果:" + decrypted);
    }
}

关键说明

  • 字符编码全程使用UTF-8,与PHP默认字符串编码保持一致
  • Java的PKCS5Padding与PHP的默认填充PKCS7Padding等价,可互相兼容
  • 严格复刻PHP的双重base64编码逻辑,确保加密结果完全一致
  • 密钥和IV的生成逻辑与PHP完全对齐,保证加解密的一致性

内容的提问来源于stack exchange,提问作者Emily

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.24 11:44:51