
本文详解如何使 PHP 成功解密 Go(使用 AES-128-CBC + PKCS#5 填充 + 随机 IV)生成的十六进制编码密文,重点解决 openssl_decrypt 返回 false 的常见原因:错误的算法标识与缺失 OPENSSL_RAW_DATA 标志。
本文详解如何使 php 成功解密 go(使用 aes-128-cbc + pkcs#5 填充 + 随机 iv)生成的十六进制编码密文,重点解决 `openssl_decrypt` 返回 `false` 的常见原因:错误的算法标识与缺失 `openssl_raw_data` 标志。
Go 示例代码中虽声明 key = "abcdabcdabcdabcd"(16 字节),但 AES 密钥长度决定实际算法:16 字节 → AES-128,而非 AES-256。PHP 端若指定 'aes-256-cbc' 会导致底层密钥扩展失败,从而解密失败。必须统一为 'aes-128-cbc'。
此外,Go 使用 hex.EncodeToString() 输出十六进制字符串,PHP 用 hex2bin() 还原为原始二进制数据(含前置 16 字节 IV + 后续密文)。而 openssl_decrypt() 默认期望 Base64 编码输入;直接传入原始二进制密文时,必须显式传入 OPENSSL_RAW_DATA 标志,否则函数静默失败并返回 false。
以下是修正后的完整 PHP 解密逻辑(可直接用于 Laravel 或原生 PHP):
public function decodeFromGolang()
{
// Go 输出的十六进制密文(含 IV + 密文)
$strFromGolang = 'efb5e55e9d2d15e6a61dcfeef322b0da839674e76666962d41f6a00a04d84adf';
// 1. 十六进制解码为原始二进制
$decoded = hex2bin($strFromGolang);
// 2. 提取前 16 字节为 IV,剩余为密文
$iv = substr($decoded, 0, 16);
$ciphertext = substr($decoded, 16);
// 3. 使用 AES-128-CBC + OPENSSL_RAW_DATA 解密
$key = 'abcdabcdabcdabcd'; // 16 字节密钥 → AES-128
$plaintext = openssl_decrypt(
$ciphertext,
'aes-128-cbc', // ⚠️ 关键:不是 aes-256-cbc
$key,
OPENSSL_RAW_DATA, // ⚠️ 关键:告知 OpenSSL 输入为原始二进制
$iv
);
if ($plaintext === false) {
throw new RuntimeException('Decryption failed: ' . openssl_error_string());
}
echo "Decrypted: " . $plaintext; // 输出:hello world
}
注意事项与验证要点:
- ✅ 密钥长度必须严格匹配:16 字节 → aes-128-cbc;24 字节 → aes-192-cbc;32 字节 → aes-256-cbc。
- ✅ Go 的 PKCS5Padding 等价于 PKCS#7(块大小为 16),PHP 的 openssl_decrypt 默认支持,无需额外处理填充。
- ✅ IV 必须与加密时完全一致(Go 中 rand.Read(iv) 生成的随机值已拼接在密文前,PHP 正确提取即可)。
- ✅ 若需在 PHP 中加密后被 Go 解密,需反向确保:使用 openssl_encrypt(..., 'aes-128-cbc', $key, OPENSSL_RAW_DATA, $iv),再 bin2hex($iv . $ciphertext) 输出。
通过同步算法标识与数据格式标志,即可实现 Go ↔ PHP 的 AES-CBC 安全、可靠互操作。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











