【问题标题】:AES Encrypt and Decrypt between C# and PHP MCryptC# 和 PHP MCrypt 之间的 AES 加密和解密
【发布时间】:2023-03-23 01:20:01
【问题描述】:

我似乎在获取 AES256 字符串以在 PHP 和 .NET 应用程序之间进行解码时遇到问题。我在 .Net 应用程序中收到一条错误消息,指出“填充无效且无法删除”。此错误在 CrytoStream 的 using 语句中触发。工作流程非常简单。 PHP 应用程序加密一个值并将其作为 URL 参数传递给 .NET 应用程序。 .NET 应用程序需要解密该值以供以后使用。 .NET 方法适用于 .NET 到 .NET,但 PHP 到 .NET 是问题所在。

PHP 代码:

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

    $crypttext = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $text, MCRYPT_MODE_CBC, 'TripBuilder2017');
    return base64_encode($crypttext);
 }

.NET 解密方法:

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

        cipherText = cipherText.Replace(" ", "+");
        byte[] cipherBytes = Convert.FromBase64String(cipherText);
        using (Aes encryptor = Aes.Create())
        {
            Rfc2898DeriveBytes pdb = new Rfc2898DeriveBytes(EncryptionKey, saltArray);
            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;
    }

更新 我将 PHP 中的模式更改为 Rijndael256,我还将 AES 更改为 .NET 中的 RijndaelManaged。同样,我可以在 .NET 应用程序之间使用它,但不能在 PHP 应用程序中使用。我想知道 PHP 应用程序使用的填充是否存在问题。

【问题讨论】:

  • 对于 mcrypt "Rijndael256" 不是 AES,256 是指块大小,AES 只有一个块大小:128 位。您可能想要的是具有 256 位密钥大小的 AES,尽管 128 位密钥大小本质上与 256 位大小一样安全。
  • 最好不要使用mcrypt,它是废弃软件,多年未更新,不支持标准PKCS#7(née PKCS#5)填充,只有非标准空填充可以'甚至不能与二进制数据一起使用。 mcrypt 有许多出色的 bugs 可以追溯到 2003 年。请考虑使用 defuseRNCryptor,它们提供了完整的解决方案并且正在维护并且是正确的。
  • 如果给定的答案解决了你的问题,你可以accept它。如果没有,请详细说明问题所在。

标签: c# php asp.net encryption


【解决方案1】:

我在消息后完全更新了答案:-)

php:

function encrypt($text) 
    {

    //$key = "M2AZULUALPHA"; //  type 2 -- mcrypt_encrypt(): Key of size 12 not supported by this algorithm. Only keys of sizes 16, 24 or 32 supported -- at line 7
    $key = "M2AZULUALPHA1234";
    //$vi ='TripBuilder2017'; // type 2 -- mcrypt_encrypt(): Received initialization vector of size 15, but size 16 is required for this encryption mode -- at line 9
    $vi ='TripBuilder20170';
    $block = mcrypt_get_block_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
    $padding = $block - (strlen($text) % $block);
    $text .= str_repeat(chr($padding), $padding);
    $crypttext = base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $text, MCRYPT_MODE_CBC, $vi));
    return $crypttext;
    }

    $result = encrypt("abcdcddsfdafdfe");
    echo"$result";

输出为“pPPH8amRhqbdX6D83jr74A=="

c# 与RijndaelManaged

public String Decrypt(string cipherText)
        {
            var result = "";
            var cypher = Convert.FromBase64String(cipherText);
            var encoding = System.Text.Encoding.UTF8;
            var Key = encoding.GetBytes("M2AZULUALPHA1234");
            var IV = encoding.GetBytes("TripBuilder20170"); 
            using (var rj = new RijndaelManaged())
            {
                rj.Padding = PaddingMode.PKCS7;
                rj.Mode = CipherMode.CBC;
                rj.KeySize = 256;
                rj.Key = Key;
                rj.IV = IV;
                var ms = new MemoryStream(cypher);
                using (var cs = new CryptoStream(ms, rj.CreateDecryptor(Key, IV), CryptoStreamMode.Read))
                using (var sr = new StreamReader(cs))
                    result = sr.ReadToEnd();
            }

            return result;
        }

测试:

var result = Decrypt("pPPH8amRhqbdX6D83jr74A==");
Debug.WriteLine(result);

输出是“abcdcddsfdafdfe”

【讨论】:

  • 在这里大放异彩+1。
  • 我添加了密码模式,但是将 Blocksize 更改为 256 会生成错误,指出“指定的块大小对此算法无效。”
  • 为什么不使用 RijndaelManaged?
  • 我刚刚尝试过,结果相同。从 .NET 到 .NET,但不能从 PHP 到 .NET
  • @ChrisLombardi 考虑使用RNCryptor,它支持多个平台,因此它非常适合跨平台加密。它还“免费”添加了密钥派生、身份验证和版本控制。
猜你喜欢
  • 2014-02-06
  • 1970-01-01
  • 2014-06-28
  • 1970-01-01
  • 2014-09-12
  • 1970-01-01
  • 2011-01-24
  • 2015-11-10
  • 2012-11-06
相关资源
最近更新 更多