I am trying to convert the following php code to C#:
$m_params = urlencode(base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_256,$key, json_encode($arParams), MCRYPT_MODE_ECB)));
What the documentation says:
m_params : A JSON array of data of additional parameters encrypted using the Rijindael-256 algorithm and encoded using a base64 algorithm.
What I've assumed?
Step 1: Create an array of params i.e. $arParams For php its declared like:
$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',
);
For C# I've declared it like this:
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"},
};
Step 2: Encode to JSON string, I've used JsonConvert.SerializeObject(additional_params);
Step 3: Encrypt the result using RIJNDAEL-256 Algorithm using ECB (I've used CBC as well)
Step 4: Encode the result using base64. I've used Convert.ToBase64String(encrypted);
Step 5: Url encode the result. I've used HttpUtility.UrlEncode(base64String, Encoding.UTF8);
Step 6: Save the result in m_params
My current code looks like this:
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;
}
}
Its not giving the same output. Am I missing something??
RijndaelManaged: This algorithm supports key lengths of 128, 192, or 256 bits; defaulting to 256 bits. In .NET Framework, this algorithm supports block sizes of 128, 192, or 256 bits; defaulting to 128 bits (Aes-compatible). In .NET Core, it is the same as AES and supports only a 128-bit block size. Thus in .Net Framework you must explicitly set theBlockSizeto 256. In .Net core you're out of luck and must use a third-party library.mcryptin the PHP code uses Zero padding, in the C# code PKCS7 is applied which therefore needs to be changed toPaddingMode.Zeros(although PKCS7 is the more reliable padding). Why do you need the methodsCreateMD5andCreateKey? In the PHP code no key is derived. Apart from that, the corresponding definitions are missing in your post.additional_paramsinstantiation the variable names (success_urletc.) are not contained and therefore not in the serialization. More useful here is e.g. an anonymous type likevar additional_params = new {success_url = "...", fail_url = "...", status_url = "..."};For serialization, note that in PHP / is often serialized as \/, while in C# it is simply serialized as /, but this can be corrected manually (e.g. withReplace("/", "\\/")).