openssl_decrypt无法解密命令行加密内容的技术问题排查
问题定位与解决:Bash与PHP AES-256-CTR解密不一致
问题现象
- Bash脚本
encrypt.bash和decrypt.bash可正常完成加密、解密流程,输出原始明文 - 同一份加密文件
encrypted.txt,用PHP的openssl_decrypt解密时输出乱码
核心原因
两者的密钥处理逻辑不一致:
- Bash中
openssl enc使用-k参数时,不会直接把传入的字符串作为加密密钥,而是会自动生成盐值(写入加密文件头部),再通过MD5密钥派生函数(KDF),将密码+盐值转换为实际的AES密钥 - PHP的
openssl_decrypt默认直接使用传入的$key字符串作为原始密钥,没有执行密钥派生步骤,导致两边使用的实际密钥不匹配,解密后出现乱码
解决方案
提供两种可选修正方案,按需选择:
方案1:修改Bash脚本,直接使用原始密钥(推荐)
将Bash脚本中的-k参数替换为-K(大写K),直接传入密钥的十六进制值,跳过密钥派生流程,和PHP的逻辑对齐。
修改后的encrypt.bash:
#!/bin/bash message="This is my message, I hope you can see it. It's very long now." key="sup3r_s3cr3t_p455w0rd" echo "$message" | openssl enc \ -aes-256-ctr \ -e \ -K $(echo -n "$key" | xxd -p) \ -iv "504914019097319c9731fc639abaa6ec" \ -out encrypted.txt
修改后的decrypt.bash:
#!/bin/bash key="sup3r_s3cr3t_p455w0rd" decrypted=$(openssl enc \ -aes-256-ctr \ -d \ -K $(echo -n "$key" | xxd -p) \ -iv "504914019097319c9731fc639abaa6ec" \ -in encrypted.txt) echo "Decrypted message: $decrypted"
此时原PHP脚本decrypt.php无需修改,即可正常解密。
方案2:修改PHP脚本,兼容Bash的密钥派生逻辑
如果需要保留已生成的encrypted.txt,可以在PHP中模拟Bash的密钥派生流程,提取加密文件头部的盐值,再生成匹配的密钥:
修改后的decrypt.php:
<?php $key = "sup3r_s3cr3t_p455w0rd"; $encrypted = file_get_contents("encrypted.txt"); // 提取文件头中的盐值:前8字节为固定标识"Salted__",后续8字节是盐 $salt = substr($encrypted, 8, 8); // 去掉文件头,保留实际加密数据 $encryptedData = substr($encrypted, 16); // 模拟openssl命令行的MD5密钥派生逻辑 $derivedKey = ''; $temp = ''; // AES-256需要32字节密钥,循环生成直到满足长度 while (strlen($derivedKey) < 32) { $temp = md5($temp . $key . $salt, true); $derivedKey .= $temp; } $aesKey = substr($derivedKey, 0, 32); $iv = hex2bin("504914019097319c9731fc639abaa6ec"); $decrypted = openssl_decrypt( $encryptedData, "aes-256-ctr", $aesKey, OPENSSL_RAW_DATA, $iv ); echo "Decrypted message: $decrypted"; ?>
内容的提问来源于stack exchange,提问作者Greg
相关产品推荐
相关产品推荐

