c# MCRYPT_RIJNDAEL_256 Encryption Decryption Class in php

c# MCRYPT_RIJNDAEL_256 Encryption Decryption Class in php



I am trying to convert c# application into php but I stuck at a place where C# provides Security class for Encryption and decryption based on RIJNDAEL algo. I am trying to convert into php.



Note: I am Using php 7.2 so mcrypt is deprecated for this version.



C# code


using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;

namespace pharmarackencryption

class Program

private const string initVector = "aw90rela942f65u2";

// This constant is used to determine the keysize of the encryption algorithm.
private const int keysize = 256;

public static string Encrypt(string plainText, string passPhrase = "testing")

byte initVectorBytes = Encoding.UTF8.GetBytes(initVector);
byte plainTextBytes = Encoding.UTF8.GetBytes(plainText);
PasswordDeriveBytes password = new PasswordDeriveBytes(passPhrase, null);
byte keyBytes = password.GetBytes(keysize / 8);
RijndaelManaged symmetricKey = new RijndaelManaged();
symmetricKey.Mode = CipherMode.CBC;
ICryptoTransform encryptor = symmetricKey.CreateEncryptor(keyBytes, initVectorBytes);
MemoryStream memoryStream = new MemoryStream();
CryptoStream cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write);
cryptoStream.Write(plainTextBytes, 0, plainTextBytes.Length);
cryptoStream.FlushFinalBlock();
byte cipherTextBytes = memoryStream.ToArray();
memoryStream.Close();
cryptoStream.Close();
return Convert.ToBase64String(cipherTextBytes);


public static string Decrypt(string cipherText, string passPhrase = "testing")

byte initVectorBytes = Encoding.ASCII.GetBytes(initVector);
byte cipherTextBytes = Convert.FromBase64String(cipherText);
PasswordDeriveBytes password = new PasswordDeriveBytes(passPhrase, null);
byte keyBytes = password.GetBytes(keysize / 8);
RijndaelManaged symmetricKey = new RijndaelManaged();
symmetricKey.Mode = CipherMode.CBC;
ICryptoTransform decryptor = symmetricKey.CreateDecryptor(keyBytes, initVectorBytes);
MemoryStream memoryStream = new MemoryStream(cipherTextBytes);
CryptoStream cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read);
byte plainTextBytes = new byte[cipherTextBytes.Length];
int decryptedByteCount = cryptoStream.Read(plainTextBytes, 0, plainTextBytes.Length);
memoryStream.Close();
cryptoStream.Close();
return Encoding.UTF8.GetString(plainTextBytes, 0, decryptedByteCount);


static void Main(string args)

Program p = new Program();
string enc_password = Encrypt("437217");
string dec_password = Decrypt("C9xJGa03dRQx9ePm0nLnHg==");
Console.WriteLine(enc_password);
Console.WriteLine(dec_password);





Encryption : C9xJGa03dRQx9ePm0nLnHg==



I found some what similar code in php like



PHP code:


<?php
// key/iv in ASCII binary data, $str base64
function decrypt_stuff($key, $str, $iv)
// $plaintext_dec = mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $key, base64_decode($str), MCRYPT_MODE_CBC, $iv);
$plaintext_dec = openssl_decrypt(base64_decode($str), "aes-256-cbc", $key, OPENSSL_RAW_DATA

// key/iv in ascii binary data, $str ascii
function encrypt_stuff($key, $str, $iv)
// $ciphertext = base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key, $str, MCRYPT_MODE_CBC, $iv));
if (($l = (strlen($str) & 15)) > 0) $str .= str_repeat(chr(0), 16 - $l);
$ciphertext = base64_encode(openssl_encrypt($str, "aes-256-cbc", $key, OPENSSL_RAW_DATA

echo encrypt_stuff("testing","437217","aw90rela942f65u2");
//Result : LTbhEHjFgfa5PDJQXJEdKQ==



Both are going same thing but still result is different





You can move back to version 7.0, there is not a major difference but you will find mcrypt in that version
– Waqar Adil
Sep 5 '18 at 9:30





openssl_encrypt is alternative to mcrypt
– Juned Ansari
Sep 5 '18 at 10:06





Thanks i never knew that.
– Waqar Adil
Sep 5 '18 at 10:54





you might want to double-check padding
– sh4dowb
Sep 7 '18 at 10:18





@sh4dowb, I already checked padding but still results are different
– Juned Ansari
Sep 7 '18 at 10:26




4 Answers
4



Your PHP code produces different results because you're not using the same key. In your C# code you're using PasswordDeriveBytes to create the key, which is Microsoft's implementation of PBKDF1.


PasswordDeriveBytes



PHP doesn't support PBKDF1, but we could write a function that is compatible with C#. The code below is inspired from this great answer by Maarten Bodewes, translated to PHP.


function passwordDeriveBytes($password, $salt, $iterations = 100, $len = 32)
$key = $password . $salt;
for($i = 0; $i < $iterations; $i++)
$key = sha1($key, true);

if (strlen($key) < $len)
$hx = passwordDeriveBytes($password, $salt, $iterations - 1, 20);
$counter = 0;
while (strlen($key) < $len)
$counter += 1;
$key .= sha1($counter . $hx, true);


return substr($key, 0, $len);



Also, you're bese64 encoding and padding your data manually. You're preforming zero byte padding, but in your C# code you're using PKCS7 (the default and preferred) padding. It's best to let openssl pad and encode your data.


openssl


function encrypt_stuff($key, $str, $iv)
return openssl_encrypt($str, "aes-256-cbc", $key, 0, $iv);


function decrypt_stuff($key, $str, $iv)
return openssl_decrypt($str, "aes-256-cbc", $key, 0, $iv);



Using the key derived from passwordDeriveBytes, this PHP code produces the same results as your C# code.


passwordDeriveBytes


$key = passwordDeriveBytes("testing", null);
$enc = encrypt_stuff($key,"437217","aw90rela942f65u2");
echo $enc;
//C9xJGa03dRQx9ePm0nLnHg==



However, I don't recommend using this code for the following reasons.



It's best to use PBKDF2 for your key. You can use Rfc2898DeriveBytes in C#:


Rfc2898DeriveBytes


Rfc2898DeriveBytes kdf = new Rfc2898DeriveBytes(password, salt, iterations);
byte key = kdf.GetBytes(32);



and hash_pbkdf2 in PHP:


hash_pbkdf2


$key = hash_pbkdf2("sha1", $password, $salt, $iterations, 32, true);



The salt should be at least 8 bytes long, and the number of iterations should be at least 10,000.



You're not using a salt. You should use a random salt for each password, it makes your keys stronger.



You're using a static IV. The IV should be unique and unpredictable. You can create a random IV with RNGCryptoServiceProvider:


RNGCryptoServiceProvider


byte iv = new byte[16];
RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
rng.GetBytes(iv);



and openssl_random_pseudo_bytes:


openssl_random_pseudo_bytes


$iv = openssl_random_pseudo_bytes(16);



You could use this code for the salt too.



You're not using authenticated encryption. If you're using PHP 7 you could use GCM, but unfortunately .NET doesn't provide any AEAD algorithms. However, you could use bouncycastle, if you choose to use authenticated encryption.



But your encryption code should produce different results every time you use it, because you should be using a random IV. You can decrypt the ciphertext correctly if you have the IV. The IV doesn't have to be secret; you could store it next to the ciphertext.



If you were using mcrypt with MCRYPT_RIJNDAEL_256, you could still make your PHP code compatible with C#, as RijndaelManaged supports 256 bit block size.


mcrypt


MCRYPT_RIJNDAEL_256


RijndaelManaged


symmetricKey.BlockSize = 256;



However you shouldn't use mcrypt because it's not maintained, and it's deprecated in PHP 7.


mcrypt





your php script returns "R6CjRlJr+2fXh8ic6JeZBA==" not "C9xJGa03dRQx9ePm0nLnHg==" please check it.
– Juned Ansari
Sep 10 '18 at 9:02






To be honest, I didn't use your padding method. I've updated my answer to produce the required result.
– t.m.adam
Sep 10 '18 at 11:04



I am not familiar with the C# end of this question. However I will point out some information that may be relevant to your problem.


MCRYPT_RIJNDAEL_256


aes-256-cbc


MCRYPT_RIJNDAEL_128


MCRYPT_RIJNDAEL_128


aes-256-cbc



So for these reasons aes-256-cbc can not be used with MCRYPT_RIJNDAEL_256. They simply are not the same thing.


aes-256-cbc


MCRYPT_RIJNDAEL_256



This one is redundant. If you are using the aes-256-cbcyou need to make sure that you are using a 256 bit key. Obviously make sure that your are using the same key to encrypt and decrypt. Make sure your IV is the correct IV. I would make them both static for testing. Once you get it working tinker around with adding the IV to the cipher string on encrypt and separating the IV from the cipher text on decrypt


aes-256-cbc



Use openssl_random_pseudo_bytes() to generate your 256 bit(32 byte)key. You can also use openssl_random_pseudo_bytes() to generate your IV.


openssl_random_pseudo_bytes()


openssl_random_pseudo_bytes()



On a side note. I would highly recommend using the LibSodium library. It is now native on the latest versions of PHP and has a C# library as well. You can find it on Github easy enough.



Once you get this going I would look at learning how to Authenticate/Verify your encryption. Here is a good starting link for that. Authentication Read



Hope that helps.



It is not recommended to store passwords at the database using an reversible algo, passwords should be stored using expensive hashes. You should consider switching your password storage to a hash like Argon2.



Check this: http://php.net/manual/en/function.password-hash.php



mcrypt has been moved. not removed. you may try installing this


sudo apt-get -y install gcc make autoconf libc-dev pkg-config
sudo apt-get -y install php7.2-dev
sudo apt-get -y install libmcrypt-dev
sudo pecl install mcrypt-1.0.1



PS: not tested





I am using windows
– Juned Ansari
Sep 5 '18 at 9:33





openssl_encrypt is alternative to mcrypt
– Juned Ansari
Sep 5 '18 at 9:36



Thanks for contributing an answer to Stack Overflow!



But avoid



To learn more, see our tips on writing great answers.



Some of your past answers have not been well-received, and you're in danger of being blocked from answering.



Please pay close attention to the following guidance:



But avoid



To learn more, see our tips on writing great answers.



Required, but never shown



Required, but never shown




By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Popular posts from this blog

𛂒𛀶,𛀽𛀑𛂀𛃧𛂓𛀙𛃆𛃑𛃷𛂟𛁡𛀢𛀟𛁤𛂽𛁕𛁪𛂟𛂯,𛁞𛂧𛀴𛁄𛁠𛁼𛂿𛀤 𛂘,𛁺𛂾𛃭𛃭𛃵𛀺,𛂣𛃍𛂖𛃶 𛀸𛃀𛂖𛁶𛁏𛁚 𛂢𛂞 𛁰𛂆𛀔,𛁸𛀽𛁓𛃋𛂇𛃧𛀧𛃣𛂐𛃇,𛂂𛃻𛃲𛁬𛃞𛀧𛃃𛀅 𛂭𛁠𛁡𛃇𛀷𛃓𛁥,𛁙𛁘𛁞𛃸𛁸𛃣𛁜,𛂛,𛃿,𛁯𛂘𛂌𛃛𛁱𛃌𛂈𛂇 𛁊𛃲,𛀕𛃴𛀜 𛀶𛂆𛀶𛃟𛂉𛀣,𛂐𛁞𛁾 𛁷𛂑𛁳𛂯𛀬𛃅,𛃶𛁼

Edmonton

Crossroads (UK TV series)