繁体   English   中英

AES-256-CBC解密错误说明填充无效,无法删除

[英]AES-256-CBC Decrypt Error Stating Padding is invalid and cannot be removed

我有一个使用openSSL的PHP​​应用程序,它使用Base64编码将AES-256-CBC加密的字符串发送到.NET应用程序。 我启动了解密方法,但是当我尝试实际解密数据时,我总是出错。 错误状态为“填充无效且无法删除”。 我在这里做错了什么?

PHP函数生成的加密的Base64值是:p07cNwcvcYLxvYHCUsmZqKYr40IXXYjEHr7r + JdgXiJT5 / wpDSDmr48JLOXyNEL7

关键是:M2AZULUALPHA

盐是:TripBuilder2017x

PHP函数是:

function encrypt($text) {
$key = "M2AZULUALPHA";
$block = mcrypt_get_block_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CBC);
$padding = $block - (strlen($text) % $block);
$text .= str_repeat(chr($padding), $padding);

$crypttext = openssl_encrypt($text,'aes-256-cbc', $key,  OPENSSL_RAW_DATA, 'TripBuilder2017x');
return base64_encode($crypttext);

}

.NET解密功能:

 private string Decrypt(string cipherText)
        {
            string EncryptionKey = "M2AZULUALPHA";
            byte[] saltArray = Encoding.ASCII.GetBytes("TripBuilder2017x");


            byte[] cipherBytes = Convert.FromBase64String(cipherText);
            using (Aes encryptor = Aes.Create())
            {
                Rfc2898DeriveBytes pdb = new Rfc2898DeriveBytes(EncryptionKey, saltArray);
                encryptor.Mode = CipherMode.CBC;
                encryptor.BlockSize = 128;
                encryptor.KeySize = 256;
                encryptor.Padding = PaddingMode.PKCS7;
                encryptor.Key = pdb.GetBytes(32);
                encryptor.IV = pdb.GetBytes(16);

                using (MemoryStream ms = new MemoryStream())
                {
                    using (CryptoStream cs = new CryptoStream(ms, encryptor.CreateDecryptor(), CryptoStreamMode.Write))
                    {
                        cs.Write(cipherBytes, 0, cipherBytes.Length);
                        cs.Close();
                    }
                    cipherText = Encoding.Unicode.GetString(ms.ToArray());
                }


            }
            return cipherText;
        }

更新我去了一个在线openSSL解密工具,输入了IV,Key和base64文本。 它生成了正确的字符串,但是字符串中有一些奇怪的块。

更新2这是更新的PHP代码。 我也将密钥大小增加到16个字节。 我仍然收到相同的错误。

$key = "M2AZULUALPHAECHO";
$salt = "TripBuilder2017x";
$mode = "aes-256-cbc";
$text = "BrassMonkey";

function encrypt($text,$key,$salt,$mode) {

    return base64_encode(encryptplain($text,$key,$salt,$mode));
}

function encryptplain($text,$key,$salt,$mode) {


    $block = mcrypt_get_block_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
    $padding = $block - (strlen($text) % $block);
    $text .= str_repeat(chr($padding), $padding);

    $crypttext = openssl_encrypt($text, $mode, $key, 1, $salt);
    return ($crypttext);
}

更新3:我的.NET代码

private string Decrypt(string cipherText)
        {
            string EncryptionKey = "M2AZULUALPHAECHO";
            byte[] saltArray = Encoding.ASCII.GetBytes("TripBuilder2017x");

            byte[] cipherBytes = Convert.FromBase64String(cipherText);
            using (Aes encryptor = Aes.Create())
            {

                encryptor.Mode = CipherMode.CBC;
                encryptor.BlockSize = 128;
                encryptor.KeySize = 256;
                encryptor.Padding = PaddingMode.PKCS7;
                encryptor.Key = Encoding.ASCII.GetBytes(EncryptionKey);
                encryptor.IV = saltArray;

                using (MemoryStream ms = new MemoryStream())
                {
                    using (CryptoStream cs = new CryptoStream(ms, encryptor.CreateDecryptor(), CryptoStreamMode.Write))
                    {
                        cs.Write(cipherBytes, 0, cipherBytes.Length);
                        cs.Close();
                    }
                    cipherText = Encoding.Unicode.GetString(ms.ToArray());
                }


            }
            return cipherText;
        }

我可以看到几个眼前的问题:

  1. 您的C#解密代码使用PBKDF2从密码和Salt 导出 AES密钥和IV,而您的PHP加密代码直接将密码和salt用作AES密钥和IV。 如果要使其正常工作,则需要在两个地方使用相同的逻辑。
  2. 在计算块长度并填充输入时,您在PHP代码中指定了错误的加密算法-Rijndael的各种版本均根据其长来命名,而AES的所有版本均具有128位的块长(即Rijndael -128)并使用不同的密钥长度。 因此,如果需要适当的填充,则需要指定MCRYPT_RIJNDAEL_128。
  3. 除非您还指定了OPENSSL_ZERO_PADDING标志,否则您不应在加密过程中自行填充-如果您未指定此标志,则OpenSSL将在输入文本中添加其自己的 PKCS#7填充,将其扩展另一个块,然后解密逻辑将仅去除该部分,而忽略您手动添加的填充(并导致您使用在线OpenSSL解密工具观察到的“字符串中的怪异块”)。
  4. 您需要确保指定的AES密钥大小实际上与您指定的算法匹配-PHP的openssl_encrypt()函数扩展了密钥大小(使用空字节)以匹配您指定的算法,而C#将自动调整算法以匹配您提供的算法密钥大小。 在这种情况下,您的C#代码实际上正在执行AES-128解密,这与在您的PHP代码中进行的AES-256加密不兼容。

其他说明:

  1. 如果您希望从openssl_encrypt()获得Base64编码的结果,则可以省略OPENSSL_RAW_DATA标志,它将返回Base64编码的密文。
  2. 问题1的正确解决方案应该是在两个地方都执行密钥派生,或者使用二进制密钥和IV值-明文密钥的熵要小得多,安全性也要差得多。
  3. 您不应该在代码中对密钥和IV进行硬编码-密钥应作为参数提供,并且IV应该随机生成并随后与密文相关联。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM