Php Can';t解密AES加密字符串

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

我正在使用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);
在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());
    }
}