求对应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);
关键说明
- 密文与Tag分离:从
encryptedData末尾截取对应长度的Tag,剩余部分为真实密文 - 密钥匹配:Java中
SecretKeySpec会根据密钥字节长度自动选择AES-128或AES-256,PHP需对应指定加密算法 - 字符编码:确保Java中
key.getBytes()使用的编码与PHP一致(建议统一为UTF-8) - 错误排查:取消注释
openssl_error_string()可获取具体解密错误信息,方便定位问题
内容的提问来源于stack exchange,提问作者Franck Dupont
相关产品推荐
相关产品推荐

