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

求对应Java AES/GCM解密函数的PHP实现及问题排查

AES/GCM Java解密函数转PHP实现问题

现有一段Java AES/GCM解密函数,需要对应的PHP实现,我自己编写的PHP解密函数始终返回“not ok”,请帮忙解决。

Java解密代码

public String deciphering(String text,String key) {

    String[] parts = text.split(":");
    byte[] iv = Base64.getDecoder().decode(parts[0]);
    byte[] encryptedText = Base64.getDecoder().decode(parts[1]);

    Cipher cipher = Cipher.getInstance(ALGORITHM);
    GCMParameterSpec spec = new GCMParameterSpec(TAG_LENGTH_BIT, iv);
    cipher.init(Cipher.DECRYPT_MODE, getSecretKey(key), spec);

    byte[] decryptedText = cipher.doFinal(encryptedText);
    return new String(decryptedText);
}

private SecretKey getSecretKey(String key) {
    return new SecretKeySpec(key.getBytes(), ALGORITHM_TYPE);
}

// 常量定义
ALGORITHM = "AES/GCM/NoPadding";
ALGORITHM_TYPE = "AES";

本人编写的PHP解密代码(返回“not ok”)

function deciphering($text, $key) {

    list($ivBase64, $encryptedTextBase64) = explode(":", $text);

    $iv = base64_decode($ivBase64);
    $encryptedText = base64_decode($encryptedTextBase64);

    $cipher = 'aes-128-gcm';

    if (openssl_decrypt($encryptedText, $cipher, $key, OPENSSL_RAW_DATA, $iv)) {
        echo "ok";
    } else {
        echo "not ok";
    }
}
deciphering($text, $key);

问题分析与修正代码

核心问题点

Java的GCM模式加密输出是**密文+认证标签(Tag)**的组合,而PHP的openssl_decrypt要求密文和Tag分离传递,这是导致解密失败的主要原因。另外需注意密钥长度与AES算法位数的匹配、字符编码一致性。

修正后的PHP代码

function deciphering($text, $key) {
    list($ivBase64, $encryptedDataBase64) = explode(":", $text);

    $iv = base64_decode($ivBase64);
    $encryptedData = base64_decode($encryptedDataBase64);

    // 对应Java中的TAG_LENGTH_BIT,通常为128位(16字节),请根据实际值调整
    $tagLength = 16;
    // 分离密文和Tag:Java输出是密文在前,Tag在后
    $encryptedText = substr($encryptedData, 0, -$tagLength);
    $tag = substr($encryptedData, -$tagLength);

    // 根据密钥字节长度选择对应AES版本:16字节用aes-128-gcm,32字节用aes-256-gcm
    $keyBytes = mb_strlen($key, '8bit');
    $cipher = $keyBytes == 16 ? 'aes-128-gcm' : ($keyBytes == 32 ? 'aes-256-gcm' : '');
    if (empty($cipher)) {
        echo "密钥长度错误,需为16或32字节";
        return false;
    }

    // 执行解密
    $decrypted = openssl_decrypt($encryptedText, $cipher, $key, OPENSSL_RAW_DATA, $iv, $tag);

    if ($decrypted !== false) {
        echo "ok";
        return $decrypted;
    } else {
        echo "not ok";
        // 打印错误信息用于排查(可注释)
        // echo "错误信息:" . openssl_error_string();
        return false;
    }
}

// 调用示例(需传入实际的$text和$key)
// deciphering($text, $key);

关键说明

  1. 密文与Tag分离:从encryptedData末尾截取对应长度的Tag,剩余部分为真实密文
  2. 密钥匹配:Java中SecretKeySpec会根据密钥字节长度自动选择AES-128或AES-256,PHP需对应指定加密算法
  3. 字符编码:确保Java中key.getBytes()使用的编码与PHP一致(建议统一为UTF-8)
  4. 错误排查:取消注释openssl_error_string()可获取具体解密错误信息,方便定位问题

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 00:17:12