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

PHP AES-256-CBC与Java AES/CBC/PKCS5Padding加密结果不一致

问题背景

现有可正常运行的Java AES加密逻辑:对传入密钥做SHA-256哈希,取哈希结果前24字节作为AES密钥,取哈希结果前16字节作为初始化向量IV,采用AES/CBC/PKCS5Padding模式对明文加密后返回Base64编码密文,Java实现代码如下:

public static String encrypt(String message, String sercretKey)
{
    String base64EncryptedString = "";
        MessageDigest md = MessageDigest.getInstance("SHA-256");
        byte[] digestOfPassword = md.digest(sercretKey.getBytes("utf-8"));
        byte[] keyBytes = Arrays.copyOf(digestOfPassword, 24);
        byte[] iv = Arrays.copyOf(digestOfPassword, 16);
        SecretKey key = new SecretKeySpec(keyBytes, "AES");
        javax.crypto.Cipher cipher = javax.crypto.Cipher.getInstance("AES/CBC/PKCS5Padding");
        IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);
        cipher.init(javax.crypto.Cipher.ENCRYPT_MODE, key, ivParameterSpec);
        byte[] plainTextBytes = message.getBytes("utf-8");
        byte[] buf = cipher.doFinal(plainTextBytes);
        byte[] base64Bytes = Base64.getEncoder().encode(buf);
        base64EncryptedString = new String(base64Bytes);
    return base64EncryptedString;
}

使用PHP复现该逻辑时,相同明文、密钥下加密结果和Java端完全不一致,当前PHP代码如下:

function encryptTest($sSecretKey,$sValue)
{
    $key = hash('sha256', $sSecretKey,false);
    $key = utf8_encode($key);
    $key = substr($key, 0, 24);
    $iv = substr($key, 0, 16);
    $data = $sValue;
    $outEnc = openssl_encrypt($data, "AES-256-CBC", $key, OPENSSL_RAW_DATA, $iv);
    
    return base64_encode($outEnc);
}
错误原因

PHP代码一共有3处核心逻辑和Java端不匹配:

  • SHA-256返回结果格式错误:PHP的hash()函数默认返回十六进制小写字符串,长度为64字符(对应32字节哈希值的十六进制文本表示),但Java端md.digest()返回的是长度32字节的原始二进制字节数组。额外添加的utf8_encode()是把十六进制字符串转成UTF-8编码,和Java端拿到的原始哈希二进制内容完全不符。
  • AES加密模式配置错误:Java端取SHA-256哈希前24字节作为密钥,24字节对应AES-192算法,不是AES-256。PHP中写的AES-256-CBC要求密钥长度为32字节,和Java端密钥长度不匹配,底层会自动做截断/补零处理导致结果偏差。
  • 填充规则隐式匹配验证:Java端使用的PKCS5Padding是PHP openssl扩展CBC模式的默认填充规则,不需要额外配置,但前提是密钥、IV、算法位长完全匹配才能对齐结果。
修正后的PHP代码
function encryptTest($sSecretKey, $sValue)
{
    // 第三个参数传true,让hash返回原始二进制结果,和Java端digest()返回值完全一致
    $digestOfPassword = hash('sha256', $sSecretKey, true);
    // 从原始二进制哈希中截取前24字节作为密钥,对应AES-192算法
    $keyBytes = substr($digestOfPassword, 0, 24);
    // 从原始二进制哈希中截取前16字节作为IV
    $iv = substr($digestOfPassword, 0, 16);
    // 算法改为AES-192-CBC,明文默认按UTF-8读取和Java端对齐
    $outEnc = openssl_encrypt($sValue, "AES-192-CBC", $keyBytes, OPENSSL_RAW_DATA, $iv);
    
    return base64_encode($outEnc);
}

内容的提问来源于stack exchange,提问作者Unni K S

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 04:45:37