PHP使用openssl_decrypt解密乱码 openssl_random_pseudo_bytes相关问题
问题根本原因
AES-128-CBC属于分组密码的CBC模式,加密和解密必须使用完全相同的IV(初始化向量)才能得到正确结果。你当前的代码里加密时随机生成了一个IV,解密时又重新生成了另一个完全无关的随机IV,两个IV不匹配才是解密乱码的核心原因,和openssl_random_pseudo_bytes本身的用法、IV长度设置都没有关系,就算你替换成动态计算IV长度的写法也解决不了问题。
修复方案
核心逻辑是把加密时生成的IV和密文绑定在一起存储/传输,IV本身不需要保密,直接明文拼接在密文前即可,解密时先从密文里拆分出IV再解密即可。
修正后的代码示例
function aes_encode($text, $s_key){ $iv_length = openssl_cipher_iv_length("AES-128-CBC"); $iv = openssl_random_pseudo_bytes($iv_length); // 执行加密 $encrypted = openssl_encrypt($text, "AES-128-CBC", $s_key, 0, $iv); // 把IV拼在加密结果前面,再统一做base64编码 return base64_encode($iv . $encrypted); } function aes_decode($encrypt_text, $s_key){ $decoded = base64_decode($encrypt_text); $iv_length = openssl_cipher_iv_length("AES-128-CBC"); // 从解码后的内容前N位拆分出IV,剩余部分为实际密文 $iv = substr($decoded, 0, $iv_length); $encrypted = substr($decoded, $iv_length); // 用加密时对应的IV解密 return openssl_decrypt($encrypted, "AES-128-CBC", $s_key, 0, $iv); } // 测试用例 $plaintext = "测试明文"; $s_key = "1234567890123456"; // 注意AES-128要求密钥必须为16字节长度,长度不符合也会导致解密异常 $encrypt_text = aes_encode($plaintext, $s_key); echo $encrypt_text . PHP_EOL; $decrypt_text = aes_decode($encrypt_text, $s_key); echo $decrypt_text . PHP_EOL;
额外注意事项
- 密钥长度必须和选用的加密算法匹配:AES-128要求密钥长度16字节、AES-192要求24字节、AES-256要求32字节,长度不符合时PHP底层会自动截断/补全,不同版本行为不一致易导致解密失败
openssl_encrypt和openssl_decrypt的第四个参数(options参数)两端必须保持一致,你当前使用的0是正确配置
内容的提问来源于stack exchange,提问作者park
相关产品推荐
相关产品推荐

