php到C#一个JSON数据数组,使用Rijindael-256算法加密,使用base64算法编码

php到C#一个JSON数据数组,使用Rijindael-256算法加密,使用base64算法编码,c#,php,api,encryption,aes,C#,Php,Api,Encryption,Aes,我正在尝试将以下php代码转换为C: $m_params = urlencode(base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_256,$key, json_encode($arParams), MCRYPT_MODE_ECB))); var additional_params = new object[] { new {&quo

我正在尝试将以下php代码转换为C:

 $m_params = urlencode(base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_256,$key, json_encode($arParams), MCRYPT_MODE_ECB)));
                var additional_params = new object[]
                    {
                        new {"http://google.com/new_success_url"},
                        new {"http://google.com/new_fail_url"},
                        new {"http://google.com/new_status_url"},
                    };
                string m_params ="";
                //converting to Json object additional params
                var jsonEncoded = JsonConvert.SerializeObject(additional_params);
                try
                {

                    string original = jsonEncoded;

                    // Create a new instance of the RijndaelManaged
                    // class.  This generates a new key and initialization
                    // vector (IV).
                    using (RijndaelManaged myRijndael = new RijndaelManaged())
                    {
                        var final_Key = CreateMD5(payeer.m_key + payeer.m_orderid);
                        var rfc = CreateKey(final_Key);
                        
                        // Encrypt the string to an array of bytes.
                        byte[] encrypted = EncryptStringToBytes(original, rfc[0], rfc[1]);
                        var base64String = Convert.ToBase64String(encrypted);
                        m_params = HttpUtility.UrlEncode(base64String, Encoding.UTF8);
                        // Decrypt the bytes to a string.
                        string roundtrip = DecryptStringFromBytes(encrypted, rfc[0], rfc[1]);

                        //Display the original data and the decrypted data.
                        Console.WriteLine("Original:   {0}", original);
                        Console.WriteLine("Round Trip: {0}", roundtrip);
                    }

         static byte[] EncryptStringToBytes(string plainText, byte[] Key, byte[] IV)
           {
            // Check arguments.
            if (plainText == null || plainText.Length <= 0)
                throw new ArgumentNullException("plainText");
            if (Key == null || Key.Length <= 0)
                throw new ArgumentNullException("Key");
            if (IV == null || IV.Length <= 0)
                throw new ArgumentNullException("IV");
            byte[] encrypted;
            // Create an RijndaelManaged object
            // with the specified key and IV.
            using (RijndaelManaged rijAlg = new RijndaelManaged())
            {
                rijAlg.Key = Key;
                rijAlg.IV = IV;
                rijAlg.Mode = CipherMode.ECB;
              //  rijAlg.KeySize = 256;
                rijAlg.BlockSize = 256;
                rijAlg.Padding = PaddingMode.PKCS7;
                // Create an encryptor to perform the stream transform.
                ICryptoTransform encryptor = rijAlg.CreateEncryptor(rijAlg.Key, rijAlg.IV);

                // Create the streams used for encryption.
                using (MemoryStream msEncrypt = new MemoryStream())
                {
                    using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
                    {
                        using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
                        {

                            //Write all data to the stream.
                            swEncrypt.Write(plainText);
                        }
                        encrypted = msEncrypt.ToArray();
                    }
                }
            }

            // Return the encrypted bytes from the memory stream.
            return encrypted;
        }


public static string CreateMD5(string input)
        {
            // Use input string to calculate MD5 hash
            using (System.Security.Cryptography.MD5 md5 = System.Security.Cryptography.MD5.Create())
            {
                byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes(input);
                byte[] hashBytes = md5.ComputeHash(inputBytes);

                // Convert the byte array to hexadecimal string
                StringBuilder sb = new StringBuilder();
                for (int i = 0; i < hashBytes.Length; i++)
                {
                    sb.Append(hashBytes[i].ToString("X2"));
                }
                return sb.ToString();
            }
        }
        public static dynamic CreateKey(string password)
        {
            var salt = new byte[] { 1, 2, 23, 234, 37, 48, 134, 63, 248, 4 };

            const int Iterations = 9872;
            using (var rfc2898DeriveBytes = new Rfc2898DeriveBytes(password, salt, Iterations))
            {
                var key = rfc2898DeriveBytes.GetBytes(32);
                var IV = rfc2898DeriveBytes.GetBytes(16);
                dynamic[] arr = new dynamic[2];
                arr[0] = key;
                arr[1] = IV;
                return arr;
            }
                
        }
文档内容:

 $m_params = urlencode(base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_256,$key, json_encode($arParams), MCRYPT_MODE_ECB)));
                var additional_params = new object[]
                    {
                        new {"http://google.com/new_success_url"},
                        new {"http://google.com/new_fail_url"},
                        new {"http://google.com/new_status_url"},
                    };
                string m_params ="";
                //converting to Json object additional params
                var jsonEncoded = JsonConvert.SerializeObject(additional_params);
                try
                {

                    string original = jsonEncoded;

                    // Create a new instance of the RijndaelManaged
                    // class.  This generates a new key and initialization
                    // vector (IV).
                    using (RijndaelManaged myRijndael = new RijndaelManaged())
                    {
                        var final_Key = CreateMD5(payeer.m_key + payeer.m_orderid);
                        var rfc = CreateKey(final_Key);
                        
                        // Encrypt the string to an array of bytes.
                        byte[] encrypted = EncryptStringToBytes(original, rfc[0], rfc[1]);
                        var base64String = Convert.ToBase64String(encrypted);
                        m_params = HttpUtility.UrlEncode(base64String, Encoding.UTF8);
                        // Decrypt the bytes to a string.
                        string roundtrip = DecryptStringFromBytes(encrypted, rfc[0], rfc[1]);

                        //Display the original data and the decrypted data.
                        Console.WriteLine("Original:   {0}", original);
                        Console.WriteLine("Round Trip: {0}", roundtrip);
                    }

         static byte[] EncryptStringToBytes(string plainText, byte[] Key, byte[] IV)
           {
            // Check arguments.
            if (plainText == null || plainText.Length <= 0)
                throw new ArgumentNullException("plainText");
            if (Key == null || Key.Length <= 0)
                throw new ArgumentNullException("Key");
            if (IV == null || IV.Length <= 0)
                throw new ArgumentNullException("IV");
            byte[] encrypted;
            // Create an RijndaelManaged object
            // with the specified key and IV.
            using (RijndaelManaged rijAlg = new RijndaelManaged())
            {
                rijAlg.Key = Key;
                rijAlg.IV = IV;
                rijAlg.Mode = CipherMode.ECB;
              //  rijAlg.KeySize = 256;
                rijAlg.BlockSize = 256;
                rijAlg.Padding = PaddingMode.PKCS7;
                // Create an encryptor to perform the stream transform.
                ICryptoTransform encryptor = rijAlg.CreateEncryptor(rijAlg.Key, rijAlg.IV);

                // Create the streams used for encryption.
                using (MemoryStream msEncrypt = new MemoryStream())
                {
                    using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
                    {
                        using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
                        {

                            //Write all data to the stream.
                            swEncrypt.Write(plainText);
                        }
                        encrypted = msEncrypt.ToArray();
                    }
                }
            }

            // Return the encrypted bytes from the memory stream.
            return encrypted;
        }


public static string CreateMD5(string input)
        {
            // Use input string to calculate MD5 hash
            using (System.Security.Cryptography.MD5 md5 = System.Security.Cryptography.MD5.Create())
            {
                byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes(input);
                byte[] hashBytes = md5.ComputeHash(inputBytes);

                // Convert the byte array to hexadecimal string
                StringBuilder sb = new StringBuilder();
                for (int i = 0; i < hashBytes.Length; i++)
                {
                    sb.Append(hashBytes[i].ToString("X2"));
                }
                return sb.ToString();
            }
        }
        public static dynamic CreateKey(string password)
        {
            var salt = new byte[] { 1, 2, 23, 234, 37, 48, 134, 63, 248, 4 };

            const int Iterations = 9872;
            using (var rfc2898DeriveBytes = new Rfc2898DeriveBytes(password, salt, Iterations))
            {
                var key = rfc2898DeriveBytes.GetBytes(32);
                var IV = rfc2898DeriveBytes.GetBytes(16);
                dynamic[] arr = new dynamic[2];
                arr[0] = key;
                arr[1] = IV;
                return arr;
            }
                
        }
m_params:数据的JSON数组 附加参数 使用 Rijindael-256算法及其应用 使用base64编码 算法

我的假设是什么?

步骤1:创建一个参数数组,即$arParams 对于php,其声明如下:

$arParams = array(
'success_url' => 'http://google.com/new_success_url',
'fail_url' => 'http://google.com/new_fail_url',
'status_url' => 'http://google.com/new_status_url',
);
对于C#我这样宣布:

 var additional_params = new object[]
                        {
                            new {"http://google.com/new_success_url"},
                            new {"http://google.com/new_fail_url"},
                            new {"http://google.com/new_status_url"},
                        };
步骤2:编码为JSON字符串,我使用了
JsonConvert.SerializeObject(附加参数)

第3步:使用ECB使用RIJNDAEL-256算法加密结果(我也使用了CBC)

步骤4:使用base64对结果进行编码。我使用了
Convert.ToBase64String(加密)

步骤5:Url编码结果。我使用了
HttpUtility.UrlEncode(base64String,Encoding.UTF8)

步骤6:将结果保存在
m_参数中

我当前的代码如下所示:

 $m_params = urlencode(base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_256,$key, json_encode($arParams), MCRYPT_MODE_ECB)));
                var additional_params = new object[]
                    {
                        new {"http://google.com/new_success_url"},
                        new {"http://google.com/new_fail_url"},
                        new {"http://google.com/new_status_url"},
                    };
                string m_params ="";
                //converting to Json object additional params
                var jsonEncoded = JsonConvert.SerializeObject(additional_params);
                try
                {

                    string original = jsonEncoded;

                    // Create a new instance of the RijndaelManaged
                    // class.  This generates a new key and initialization
                    // vector (IV).
                    using (RijndaelManaged myRijndael = new RijndaelManaged())
                    {
                        var final_Key = CreateMD5(payeer.m_key + payeer.m_orderid);
                        var rfc = CreateKey(final_Key);
                        
                        // Encrypt the string to an array of bytes.
                        byte[] encrypted = EncryptStringToBytes(original, rfc[0], rfc[1]);
                        var base64String = Convert.ToBase64String(encrypted);
                        m_params = HttpUtility.UrlEncode(base64String, Encoding.UTF8);
                        // Decrypt the bytes to a string.
                        string roundtrip = DecryptStringFromBytes(encrypted, rfc[0], rfc[1]);

                        //Display the original data and the decrypted data.
                        Console.WriteLine("Original:   {0}", original);
                        Console.WriteLine("Round Trip: {0}", roundtrip);
                    }

         static byte[] EncryptStringToBytes(string plainText, byte[] Key, byte[] IV)
           {
            // Check arguments.
            if (plainText == null || plainText.Length <= 0)
                throw new ArgumentNullException("plainText");
            if (Key == null || Key.Length <= 0)
                throw new ArgumentNullException("Key");
            if (IV == null || IV.Length <= 0)
                throw new ArgumentNullException("IV");
            byte[] encrypted;
            // Create an RijndaelManaged object
            // with the specified key and IV.
            using (RijndaelManaged rijAlg = new RijndaelManaged())
            {
                rijAlg.Key = Key;
                rijAlg.IV = IV;
                rijAlg.Mode = CipherMode.ECB;
              //  rijAlg.KeySize = 256;
                rijAlg.BlockSize = 256;
                rijAlg.Padding = PaddingMode.PKCS7;
                // Create an encryptor to perform the stream transform.
                ICryptoTransform encryptor = rijAlg.CreateEncryptor(rijAlg.Key, rijAlg.IV);

                // Create the streams used for encryption.
                using (MemoryStream msEncrypt = new MemoryStream())
                {
                    using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
                    {
                        using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
                        {

                            //Write all data to the stream.
                            swEncrypt.Write(plainText);
                        }
                        encrypted = msEncrypt.ToArray();
                    }
                }
            }

            // Return the encrypted bytes from the memory stream.
            return encrypted;
        }


public static string CreateMD5(string input)
        {
            // Use input string to calculate MD5 hash
            using (System.Security.Cryptography.MD5 md5 = System.Security.Cryptography.MD5.Create())
            {
                byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes(input);
                byte[] hashBytes = md5.ComputeHash(inputBytes);

                // Convert the byte array to hexadecimal string
                StringBuilder sb = new StringBuilder();
                for (int i = 0; i < hashBytes.Length; i++)
                {
                    sb.Append(hashBytes[i].ToString("X2"));
                }
                return sb.ToString();
            }
        }
        public static dynamic CreateKey(string password)
        {
            var salt = new byte[] { 1, 2, 23, 234, 37, 48, 134, 63, 248, 4 };

            const int Iterations = 9872;
            using (var rfc2898DeriveBytes = new Rfc2898DeriveBytes(password, salt, Iterations))
            {
                var key = rfc2898DeriveBytes.GetBytes(32);
                var IV = rfc2898DeriveBytes.GetBytes(16);
                dynamic[] arr = new dynamic[2];
                arr[0] = key;
                arr[1] = IV;
                return arr;
            }
                
        }
var附加参数=新对象[]
{
新{”http://google.com/new_success_url"},
新{”http://google.com/new_fail_url"},
新{”http://google.com/new_status_url"},
};
字符串m_params=“”;
//转换为Json对象附加参数
var jsonEncoded=JsonConvert.SerializeObject(附加参数);
尝试
{
字符串original=jsonEncoded;
//创建RijndaelManaged的新实例
//这将生成一个新的密钥和初始化
//载体(IV)。
使用(RijndaelManaged myRijndael=new RijndaelManaged())
{
var final_Key=CreateMD5(payer.m_Key+payer.m_orderid);
var rfc=CreateKey(最终密钥);
//将字符串加密为字节数组。
byte[]encrypted=EncryptStringToBytes(原始,rfc[0],rfc[1]);
var base64String=Convert.ToBase64String(加密);
m_params=HttpUtility.UrlEncode(base64String,Encoding.UTF8);
//将字节解密为字符串。
字符串往返=解密StringFromBytes(加密,rfc[0],rfc[1]);
//显示原始数据和解密数据。
WriteLine(“原件:{0}”,原件);
WriteLine(“往返:{0}”,往返);
}
静态字节[]加密StringToBytes(字符串明文,字节[]密钥,字节[]IV)
{
//检查参数。

如果(plainText==null | | plainText.Length如詹姆斯·K·波尔克总统的评论所述,块大小为256位的Rijndael仅在.NET Framework中受支持,而在.NET Core中不受支持。您没有指定正在运行的版本,但因为在发布的代码中使用了256位的块大小(
rijAlg.BlockSize=256;
),我假设您正在运行.NET Framework(否则,您需要应用支持块大小为256位的Rijndael的第三方库,例如BouncyCastle/C#)

两种代码使用不同的填充。
mcrypt
默认情况下应用零填充,C代码显式使用PKCS7填充(这也是C的默认值)。因此,C代码提供与PHP代码相同的结果,因此有必要在C代码中切换到零填充(应该注意,与PKCS7填充不同,零填充是不可靠的)

当实例化
附加参数时(顺便说一句,它在我的机器上不编译),变量名丢失,因此在序列化中也会丢失。可以使用匿名类型。另外,请注意
json\u encode()
转义斜杠(
/
)默认情况下,即将其转换为
\/
,这必须在C代码中手动完成,例如使用
替换(“/”,“\\/”)
。JSON序列化的一种可能实现方式是:

using Newtonsoft.Json;
...
var additionalParams = new
{
    success_url = "http://google.com/new_success_url",
    fail_url = "http://google.com/new_fail_url",
    status_url = "http://google.com/new_status_url"
};
string jsonEncoded = JsonConvert.SerializeObject(additionalParams).Replace("/", "\\/");
在PHP代码中,密钥是使用MD5摘要从密码中派生出来的。默认情况下,以十六进制字符串的形式返回结果,该字符串将16个字节的哈希值转换为32个字节的值,并作为密钥应用,因此使用AES-256。PHP用小写字母表示十六进制数字,也必须在中相应地实现C代码,例如:

using System;
using System.Text;
using System.Security.Cryptography;
...
MD5 md5 = MD5.Create();
string password = "My password"; // test password 
byte[] passwordHash = md5.ComputeHash(Encoding.UTF8.GetBytes(password));
string passwordHashHex = BitConverter.ToString(passwordHash).Replace("-", "").ToLower();  // convert byte array to lowercase hex string as in PHP
byte[] key = Encoding.UTF8.GetBytes(passwordHashHex);
如果使用
位转换器将字节数组转换为十六进制字符串,请参阅

加密的一种可能实现方式是:

using System;
using System.IO;
using System.Web;
using System.Text;
using System.Security.Cryptography;
...
byte[] encrypted = null;
using (RijndaelManaged rijndael = new RijndaelManaged())
{
    rijndael.Key = key;
    rijndael.Mode = CipherMode.ECB;           // default: CBC
    rijndael.BlockSize = 256;                 // default: 128
    rijndael.Padding = PaddingMode.Zeros;     // default: PKCS7

    ICryptoTransform encryptor = rijndael.CreateEncryptor(rijndael.Key, null);
    using (MemoryStream msEncrypt = new MemoryStream())
    {
        using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
        {
            using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
            {
                swEncrypt.Write(jsonEncoded);
            }
            encrypted = msEncrypt.ToArray();
        }
    }
}
string base64String = Convert.ToBase64String(encrypted);
string m_params = HttpUtility.UrlEncode(base64String, Encoding.UTF8);
Console.WriteLine(m_params);
其中,此代码和使用的测试密码给出以下结果:

C3pldgsLDSqfG28cbt%2BV0UIBNQT6CWN86IRWG%2bv2blTzR7Lsnra%2b2Ok35Ex9f9UbG%2BJHKGITUQ8KO3DRIRWUQWIRZYZWGBUCHNRTHADF60RGUIBDJZ2KOIHDVZLMSZTBVYIGOFIQBJBHZQ9GGTABUOA5PCMIYUEN%2BQG1MDJUNVt8N0ETXSAD6CFC1%2bguR0wZx%2FZZ2FEZAMSBBRW%3d%
根据以下PHP代码的结果:

$key = md5('My password'); // test password
$arParams = array(
    'success_url' => 'http://google.com/new_success_url',
    'fail_url' => 'http://google.com/new_fail_url',
    'status_url' => 'http://google.com/new_status_url',
);
$m_params = urlencode(base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_256,$key, json_encode($arParams), MCRYPT_MODE_ECB)));
print($m_params . "\n");
请注意,C#使用小写字母进行url编码,而PHP使用大写字母,表示相同的url编码,请参见。如果C#代码也应使用大写字母进行url编码,则可以使用正则表达式轻松实现,请参见例如


关于安全的几点意见:

PHP代码应用了不安全的ECB模式。出于安全原因,应使用带有IV的模式,例如CBC或GCM。后者提供隐式身份验证加密。IV是为每次加密随机生成的,不是秘密的,是s