Php Can';t解密AES加密字符串
我正在使用openssl\u encrypt对字符串进行加密,并在powershell中对其进行解密 在PHP中Php Can';t解密AES加密字符串,php,powershell,encryption,aes,Php,Powershell,Encryption,Aes,我正在使用openssl\u encrypt对字符串进行加密,并在powershell中对其进行解密 在PHP中 $data = "helloWorld"; $key = 'CefaiNooH4oi6oje'; $iv = 'Choodub8ahd4choo'; $data = openssl_encrypt($data, 'AES-256-CBC', $key, 0, $iv); echo base64_encode($data); 在Powershe
$data = "helloWorld";
$key = 'CefaiNooH4oi6oje';
$iv = 'Choodub8ahd4choo';
$data = openssl_encrypt($data, 'AES-256-CBC', $key, 0, $iv);
echo base64_encode($data);
在Powershell中
$data = "dnQvNEhEczBnQ0F5OEQ4Yi9tOUY4Zz09"
$data = [System.Convert]::FromBase64String($data)
$aesManaged = New-Object "System.Security.Cryptography.AesManaged"
$aesManaged.Mode = [System.Security.Cryptography.CipherMode]::CBC
$aesManaged.Padding = [System.Security.Cryptography.PaddingMode]::Zeros
$aesManaged.BlockSize = 128
$aesManaged.KeySize = 256
$aesManaged.Key = [system.Text.Encoding]::UTF8.GetBytes("CefaiNooH4oi6oje")
$aesManaged.IV = [system.Text.Encoding]::UTF8.GetBytes("Choodub8ahd4choo")
$decryptor = $aesManaged.CreateDecryptor();
$clear = $decryptor.TransformFinalBlock($data, 16, $data.Length - 16);
[System.Text.Encoding]::UTF8.GetString($clear).Trim([char]0)
然后我得到一个错误:
Exception calling "TransformFinalBlock" with "3" argument(s): "The input data is not a complete block."
这里可能有什么问题?编辑#2当你真正让解密代码工作时,我发现了为什么会出现垃圾,这让我兴奋不已,但我忽略了回答为什么会出现错误的问题:
使用“3”参数调用“TransformFinalBlock”时出现异常:“输入数据不是完整块。”
问题是您传入的数据块的长度不足以成为
块
。使用要转换为字节的原始字符串,可以得到一个24字节的数组,但块大小是16字节,因此需要一个长度为16的倍数的数组。使用正确的字符串vt/4HDs0gCAy8D8b/m9F8g==,您将得到一个16的数组,该数组可以工作(尽管需要对调用TransformFinalBlock
进行一个小的更正,但您希望使用偏移量0和输入数组的长度来调用它-我已经更新了下面的解决方案以显示这一点)
结束编辑#2
我知道了
第一个问题是:
echo base64_encode($data);
您从中获取的$data
值已进行base64编码,因此无需再次编码。如果删除该行,则将该字符串取回vt/4HDs0gCAy8D8b/m9F8g==
(请参阅链接)
为了以防万一,您需要证明发生了什么,这里有另一个链接,显示了如果您将字符串从Base64转换为字符串,然后将这些字节转换为字符串,您将得到原始的Base64编码字符串,该字符串来自对openssl_encrypt的调用
现在是解密部分(请注意,我将用C#发布代码,但如果有问题的评论,转换为powershell应该是相当简单的,我将尽力提供帮助)。我通常会创建一个解密程序并使用一个流,但我想适合您的代码,所以我使用TransformBlock
方法
string result = null;
using (var aes = new AesManaged())
{
// openssl_encrypt will zero pad a key that is not the correct length
var key = Encoding.UTF8.GetBytes("CefaiNooH4oi6oje");
if (key.Length < 32)
{
var temp = new byte[key.Length + (32 - key.Length % 32)];
Array.Copy(key, temp, key.Length);
key = temp;
}
var iv = Encoding.UTF8.GetBytes("Choodub8ahd4choo");
aes.Mode = CipherMode.CBC;
aes.KeySize = 256;
aes.Key = key;
aes.IV = iv;
aes.Padding = PaddingMode.Zeros;
var cipher = Convert.FromBase64String("vt/4HDs0gCAy8D8b/m9F8g==");
using (var decryptor = aes.CreateDecryptor())
{
var buffer = decryptor.TransformFinalBlock(cipher, 0, cipher.Length);
result = Encoding.UTF8.GetString(buffer);
}
}
这个答案可能会对您有所帮助-看起来(我刚刚检查了php源代码以验证这一点)ssl_encrypt将0填充密钥以使其具有适当的长度。您指定的密钥是16个字节,因此它将向密钥中再添加16个0字节。我仍然无法让它解码您的结果,但希望该链接可能会有帮助。我还建议您从
TransformFinalBlock
切换,这是您在最后一块数据上调用的特殊函数。相反,当我将密钥更改为32字节并切换到CryptoStream时,您可以使用它
using (var aes = new AesManaged())
{
// See sample above for setup code, omitted for brevity
using (var dest = new MemoryStream())
using (var input = new MemoryStream(cipher))
using (var cs = new CryptoStream(input, aes.CreateDecryptor(), CryptoStreamMode.Read))
{
var buffer = new byte[1024];
var read = cs.Read(buffer, 0, buffer.Length);
while(read > 0)
{
dest.Write(buffer, 0, read);
read = cs.Read(buffer, 0, buffer.Length);
}
dest.Flush();
result = Encoding.UTF8.GetString(dest.ToArray());
}
}