I have almost lost my hair, mind and everything else! I have been trying to convert this PHP function to C#:
function encrypt_decrypt($action, $string) {
$output = false;
$key = 'My strong secret key';
// initialization vector
$iv = md5(md5($key));
$output = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, md5($key), $string, MCRYPT_MODE_CBC, $iv);
$output = bin2hex($output);
return $output;
}
I have been working with Rijandel Class:
function encrypt_decrypt(string password) {
UTF8Encoding encoding = new UTF8Encoding();
// For consistency with PHP function, MD5Encrypt applies MD5 encryption and does a bin2hex
byte[] Key = Encoding.ASCII.GetBytes(MD5Encrypt(password).ToLower());
byte[] IV = Encoding.ASCII.GetBytes(MD5Encrypt(MD5Encrypt(password).ToLower()).ToLower());
RijndaelManaged rj = new RijndaelManaged();
rj.BlockSize = 256;
rj.KeySize = 256;
rj.Key = Key;
rj.IV = IV;
rj.Mode = CipherMode.CBC;
MemoryStream ms = new MemoryStream();
using (CryptoStream cs = new CryptoStream(ms, rj.CreateEncryptor(Key, IV), CryptoStreamMode.Write))
{
using (StreamWriter sw = new StreamWriter(cs))
{
sw.Write(message);
sw.Close();
}
cs.Close();
}
byte[] encoded = ms.ToArray();
string output = "";
foreach (var ele in encoded)
{
output += ele.ToString("X2");
}
return output;
}
I have been validating the output of the PHP code with that from the C# code and they do not match. (http://writecodeonline.com/php/). Any feedback would be appreciated.
There are multiple issues to be kept in mind while doing this like converting binary, checking encoding and padding issues. Since we cannot see your complete code we are helpless in this case. Check this tutorial for further info: http://blog.djekldevelopments.co.uk/?p=334
Try this instead:
using (RijndaelManaged myRijndael = new RijndaelManaged())
{
myRijndael.Key = Encoding.UTF8.GetBytes(password);
string strIv16 = "\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0";
myRijndael.IV = Encoding.UTF8.GetBytes(strIv16);
// Encrypt the string to an array of bytes.
byte[] encrypted = EncryptStringToBytes(message, myRijndael.Key, myRijndael.IV);
string output = Convert.ToBase64String(encrypted);
}
Related
I have the following lines in a PHP 7 program encrypting/decrypting data:
$key = base64_decode("mykey===");
$iv = substr(hash('sha256', "myiv======"), 0, 16);
printf(base64_encode(openssl_encrypt("hello", "aes-256-cbc", $key, OPENSSL_RAW_DATA, $iv)));
printf("<br>");
printf(openssl_decrypt(base64_decode("2XJxQXSbPuJ9LMsZ/FESGw=="), "aes-256-cbc", $key, OPENSSL_RAW_DATA, $iv));
This is working, PHP decrypts "hello" to "2XJxQXSbPuJ9LMsZ/FESGw==" and vice versa. However I'm trying to decrypt and encrypt the same data (from a Database) with C# but can't seem to figure it out. I used the following method for decryption (C#):
private string aes_decrypt(string cipherText, string key, string iv)
{
RijndaelManaged aes = new RijndaelManaged();
aes.KeySize = 256;
aes.BlockSize = 128;
aes.Mode = CipherMode.CBC;
aes.Padding = PaddingMode.None;
aes.Key = Convert.FromBase64String(key);
aes.IV = Encoding.UTF8.GetBytes(iv);
if (aes.Key.Length < 32)
{
var paddedkey = new byte[32];
Buffer.BlockCopy(aes.Key, 0, paddedkey, 0, aes.Key.Length);
aes.Key = paddedkey;
}
var decrypt = aes.CreateDecryptor();
byte[] xBuff = null;
using (var ms = new MemoryStream())
{
using (var cs = new CryptoStream(ms, decrypt, CryptoStreamMode.Write))
{
byte[] xXml = Convert.FromBase64String(cipherText);
cs.Write(xXml, 0, xXml.Length);
}
xBuff = ms.ToArray();
}
String Output = Encoding.UTF8.GetString(xBuff);
return Output;
}
But a call to this method:
string encryptionkey = "mykey===";
string encryptioniv = GenerateSHA256String("myiv======").Substring(0, 16);
string str = aes_decrypt("2XJxQXSbPuJ9LMsZ/FESGw==", encryptionkey, encryptioniv);
Console.WriteLine(#str);
returns: HellO++++??????+
The encryption method doesnt seem to work either (referenced online and modified):
private static String EncryptIt(String s, string akey, string aIV)
{
String result;
byte[] key = Convert.FromBase64String(akey);
byte[] IV = Encoding.UTF8.GetBytes(aIV);
RijndaelManaged rijn = new RijndaelManaged();
rijn.Mode = CipherMode.CBC;
rijn.Padding = PaddingMode.PKCS7;
rijn.KeySize = 256;
rijn.BlockSize = 128;
using (MemoryStream msEncrypt = new MemoryStream())
{
using (ICryptoTransform encryptor = rijn.CreateEncryptor(key, IV))
{
using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
{
using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
{
swEncrypt.Write(s);
}
}
}
result = Convert.ToBase64String(msEncrypt.ToArray());
}
rijn.Clear();
return result;
}
A call to this method: EncryptIt("hello", encryptionkey, encryptioniv); returns ul0axDR0WWGcpeijPRNusg== and not 2XJxQXSbPuJ9LMsZ/FESGw== which was generated by PHP. Anyone knows what's wrong here?
For reference, I used these methods with the IV, they are working without errors:
private string GenerateSHA256String(string inputString)
{
SHA256 sha256 = SHA256Managed.Create();
byte[] bytes = Encoding.UTF8.GetBytes(inputString);
byte[] hash = sha256.ComputeHash(bytes);
return GetStringFromHash(hash);
}
private string GetStringFromHash(byte[] hash)
{
StringBuilder result = new StringBuilder();
for (int i = 0; i < hash.Length; i++)
{
result.Append(hash[i].ToString("X2"));
}
return result.ToString();
}
Old question, but I ran into this again recently.
When using PHP 7.2 openssl_decrypt/openssl_encrypt padding as OPENSSL_RAW_DATA, it only worked for me when the chsarp AES padding was set to PaddingMode.PKCS7.
The original post has PaddingMode.None for decrypt and PaddingMode.PKCS7 for encrypt.
I seem to be having problems getting an AES256 string to decode between a PHP and .NET application. I get an error in the .Net application stating "Padding is invalid and cannot be removed." This error fires in the using statement for the CrytoStream. The workflow is pretty straight forward. The PHP application encrypts a value and passes it to the .NET application as a URL parameter. The .NET application needs to decrypt that value for later use. The .NET method works from .NET to .NET, but PHP to .NET is the problem.
The PHP code:
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);
}
The .NET Decrypt method:
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;
}
UPDATE
I changed the mode in PHP to Rijndael256 and I also changed AES to RijndaelManaged in .NET. Again, I am able to get this working between .NET applications, but not with the PHP application. I am wondering if there is an issue with the padding the PHP application is using.
I updated answer completely after messages :-)
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";
output is "pPPH8amRhqbdX6D83jr74A=="
c# with 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;
}
test:
var result = Decrypt("pPPH8amRhqbdX6D83jr74A==");
Debug.WriteLine(result);
output is "abcdcddsfdafdfe"
I did some encryption using PHP in my Database and would normally decrypt using:
$encrypt_method = "AES-256-CBC";
$secret_key = "testing";
$secret_iv = "testingyes!!!";
$key = hash('sha256', $secret_key); // hash the key
$iv = substr(hash('sha256', $secret_iv), 0, 16); // iv - encrypt method AES-256-CBC expects 16 bytes - else you will get a warning
echo(openssl_decrypt(base64_decode($data), $encrypt_method, $key, 0, $iv)); // the decrypted data
I'm trying to do the same task but with C# 2013 to decrypt the same data, any ideas?
I would encrypt in php using:
$encrypt_method = "AES-256-CBC";
$secret_key = "testing";
$secret_iv = "testingyes!!!";
$key = hash('sha256', $secret_key); // hash the key
$iv = substr(hash('sha256', $secret_iv), 0, 16); // iv - encrypt method AES-256-CBC expects 16 bytes - else you will get a warning
echo(base64_encode(openssl_encrypt($data, $encrypt_method, $key, 0, $iv))); // the encrypted data
encrypting: this is a test
gives: d0EzQ2MvMHkxRks2cXg5NkFkK2twZz09=
I tried this in C#:
public static String sha256_hash(String value)
{
StringBuilder Sb = new StringBuilder();
using (SHA256 hash = SHA256Managed.Create())
{
Encoding enc = Encoding.UTF8;
Byte[] result = hash.ComputeHash(enc.GetBytes(value));
foreach (Byte b in result)
Sb.Append(b.ToString("x2"));
}
return Sb.ToString();
}
private static String AES_decrypt(String Input)
{
RijndaelManaged aes = new RijndaelManaged();
aes.KeySize = 256;
aes.BlockSize = 256;
aes.Mode = CipherMode.CBC;
aes.Padding = PaddingMode.None;
aes.Key = Convert.FromBase64String(sha256_hash("testing"));
aes.IV = Convert.FromBase64String(sha256_hash("testingyes!!!").Substring(0, 16));
var decrypt = aes.CreateDecryptor();
byte[] xBuff = null;
using (var ms = new MemoryStream())
{
using (var cs = new CryptoStream(ms, decrypt, CryptoStreamMode.Write))
{
byte[] xXml = Convert.FromBase64String(Input);
cs.Write(xXml, 0, xXml.Length);
}
xBuff = ms.ToArray();
}
String Output = Encoding.UTF8.GetString(xBuff);
return Output;
}
string cipherData = "d0EzQ2MvMHkxRks2cXg5NkFkK2twZz09=";
string f = AES_decrypt(cipherData);
Console.Write(f);
But I'm getting error: specified key is not a valid size for this algorithm
However the key I'm using is working when I use PHP
RijndaelManaged aes = new RijndaelManaged();
aes.KeySize = 256;
aes.BlockSize = 256;
Block size should be 128 to be compatible with AES-256-CBC.
Rijndael supports variable block sizes - AES does not.
I am facing some issues in AES encryption using PHP and decode the same using C #. My reference site.
Here is the PHP code:
function encrypt_string($input, $key)
{
$iv = mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC), MCRYPT_RAND);
return preg_replace('/=/', "", base64_encode($iv . mcrypt_encrypt(MCRYPT_RIJNDAEL_128, hash("sha256", $key, true), $input, MCRYPT_MODE_CBC, $iv)));
}
function decrypt_string($input, $key)
{
$input .= "=";
$data = base64_decode($input);
$iv = substr($data, 0, mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC));
return rtrim(mcrypt_decrypt(MCRYPT_RIJNDAEL_128,hash('sha256', $key, true),substr($data, mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC)),MCRYPT_MODE_CBC,$iv),"\0");
}
Here is C# code that I tried:
private static byte[] sha256_data(string input)
{
SHA256 hash = SHA256Managed.Create();
Encoding encode = Encoding.UTF8;
return hash.ComputeHash(encode.GetBytes(input));
}
private string encode_data(string data, string key)
{
byte[] buff;
RijndaelManaged rij = new RijndaelManaged();
rij.BlockSize = 256;
rij.KeySize = 256;
rij.GenerateIV();
rij.Key = sha256_data(key);
rij.Mode = CipherMode.CBC;
ICryptoTransform encoder = rij.CreateEncryptor(rij.Key, rij.IV);
using (MemoryStream mem = new MemoryStream())
{
using (CryptoStream crypt = new CryptoStream(mem, encoder, CryptoStreamMode.Write))
{
byte[] temp = Encoding.UTF8.GetBytes(data);
crypt.Write(temp, 0, temp.Length);
}
buff = mem.ToArray();
}
return Convert.ToBase64String(result);
}
private string decode_data(string input, string key)
{
RijndaelManaged rij = new RijndaelManaged();
rij.KeySize = 256;
rij.BlockSize = 256;
rij.Key = sha256_data(key);
rij.GenerateIV();
rij.Mode = CipherMode.CBC;
rij.Padding = PaddingMode.PKCS7;
ICryptoTransform decrypter = rij.CreateDecryptor();
byte[] buff;
using (MemoryStream mem = new MemoryStream())
{
using (CryptoStream cstream = new CryptoStream(mem, decrypter, CryptoStreamMode.Write))
{
byte[] data = Convert.FromBase64String(input);
cstream.Write(data, 0, data.Length);
}
buff = mem.ToArray();
}
return Encoding.UTF8.GetString(buff);
}
What am i doing wrong?
when you decode you must parse the IV that was used for encoding not generate a new one.
I was using a REST service written in PHP in my android app without much trouble. Now I'm trying to use it in a Windows Phone app and I'm getting crazy already!
What I know so far: Silverlight will accept only Aes in CBC mode and PKCS7 padding.
What I get: "Padding is invalid and can not be removed" exception at (see full code at the bottom):
plaintext = srDecrypt.ReadToEnd();
If I crypt and decrypt in C#, using the same configs, it works fine. When I try to decript in C# from a PHP crypted string, it fails with the error mentioned above.
My PHP script do the following:
function encrypt128($message) {
$vector = "DB96A56CCA7A69FC";
$key = "6DBC44F54CA3CFDEDDCA140CA46A99C1"; // PHP md5 function leaves it in lower case, so I just copied the key from C# debug.
//PKCS7 Padding
$block = mcrypt_get_block_size('rijndael_128', 'cbc');
$pad = $block - (strlen($message) % $block);
$message.= str_repeat(chr($pad), $pad);
$cipher = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', 'cbc', '');
mcrypt_generic_init($cipher, $key, $vector);
$result = mcrypt_generic($cipher, $message);
mcrypt_generic_deinit($cipher);
return base64_encode($result);
}
And in C# (Silverlight / Windows Phone 7) I use the following to decrypt:
//Where buffer is the string data I got after calling the PHP REST service.
DecryptStringFromBytes(Convert.FromBase64String(buffer), MD5Core.GetHash("7a272d3e41372c547a272d3e41372c54"), System.Text.Encoding.UTF8.GetBytes("DB96A56CCA7A69FC"));
static string DecryptStringFromBytes(byte[] cipherText, byte[] Key, byte[] IV)
{
// Check arguments.
if (cipherText == null || cipherText.Length <= 0)
throw new ArgumentNullException("cipherText");
if (Key == null || Key.Length <= 0)
throw new ArgumentNullException("Key");
if (IV == null || IV.Length <= 0)
throw new ArgumentNullException("Key");
// Declare the string used to hold
// the decrypted text.
string plaintext = null;
// Create an RijndaelManaged object
// with the specified key and IV.
using (AesManaged rijAlg = new AesManaged())
{
rijAlg.Key = Key;
rijAlg.IV = IV;
// Create a decrytor to perform the stream transform.
ICryptoTransform decryptor = rijAlg.CreateDecryptor(rijAlg.Key, rijAlg.IV);
// Create the streams used for decryption.
using (MemoryStream msDecrypt = new MemoryStream(cipherText))
{
using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
{
using (StreamReader srDecrypt = new StreamReader(csDecrypt))
{
// Read the decrypted bytes from the decrypting stream
// and place them in a string.
plaintext = srDecrypt.ReadToEnd();
}
}
}
}
return plaintext;
}
The big question is: what am I doing wrong?
Thanks in advance!
So here is the answer:
I droped the MD5 crap out of PHP and C#, and they are now working properly.
Just in case you dropped here looking for the same answer, here is a sample code. Don't forget to make your own key and iv (although those bellow will work, is not recommended to use!)
PHP:
function encrypt128($message) {
$vector = "0000000000000000";
$key = "00000000000000000000000000000000";
$block = mcrypt_get_block_size('rijndael_128', 'cbc');
$pad = $block - (strlen($message) % $block);
$message .= str_repeat(chr($pad), $pad);
$cipher = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', 'cbc', '');
mcrypt_generic_init($cipher, $key, $vector);
$result = mcrypt_generic($cipher, $message);
mcrypt_generic_deinit($cipher);
return base64_encode($result);
}
C#:
byte[] cripted = EncryptStringToBytes("Test", System.Text.Encoding.UTF8.GetBytes("00000000000000000000000000000000"), System.Text.Encoding.UTF8.GetBytes("0000000000000000"));
Encrypt/Decrypt using PHP:
class Cipher {
private $key, $iv;
function __construct() {
$this->key = "edrtjfjfjlldldld";
$this->iv = "56666852251557009888889955123458";
}
function encrypt($text) {
$block = mcrypt_get_block_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CBC);
$padding = $block - (strlen($text) % $block);
$text .= str_repeat(chr($padding), $padding);
$crypttext = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $this->key, $text, MCRYPT_MODE_CBC, $this->iv);
return base64_encode($crypttext);
}
function decrypt($input) {
$dectext = mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $this->key, base64_decode($input), MCRYPT_MODE_CBC, $this->iv);
return $dectext;
}
}
Encrypt/Decrypt using C#:
public class RijndaelSimple
{
const string iv = "56666852251557009888889955123458";
const string key = "edrtjfjfjlldldld";
static public String EncryptRJ256(string plainText)
{
var encoding = new UTF8Encoding();
var Key = encoding.GetBytes(key);
var IV = encoding.GetBytes(iv);
byte[] encrypted;
using (var rj = new RijndaelManaged())
{
try
{
rj.Padding = PaddingMode.PKCS7;
rj.Mode = CipherMode.CBC;
rj.KeySize = 256;
rj.BlockSize = 256;
rj.Key = Key;
rj.IV = IV;
var ms = new MemoryStream();
using (var cs = new CryptoStream(ms, rj.CreateEncryptor(Key, IV), CryptoStreamMode.Write))
{
using (var sr = new StreamWriter(cs))
{
sr.Write(plainText);
}
encrypted = ms.ToArray();
}
}
finally
{
rj.Clear();
}
}
return Convert.ToBase64String(encrypted);
}
static public String DecryptRJ256(string input)
{
byte[] cypher = Convert.FromBase64String(input);
var sRet = "";
var encoding = new UTF8Encoding();
var Key = encoding.GetBytes(key);
var IV = encoding.GetBytes(iv);
using (var rj = new RijndaelManaged())
{
try
{
rj.Padding = PaddingMode.PKCS7;
rj.Mode = CipherMode.CBC;
rj.KeySize = 256;
rj.BlockSize = 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))
{
sRet = sr.ReadLine();
}
}
}
finally
{
rj.Clear();
}
}
return sRet;
}
}