C# and PHP have different AES encryption results - c#

I have same data and encryption key, same algorithm, same mode but different result.
C# Code:
string encKey = "0F777D55FDB154E7D8754C3C0E660A65";
string dataToEncrypt = "FF01083131323233333434FF020102FF030E3230313630313230313635353032FF040C313132323333343435353636FF05083131323233333434FF060F6D6173746572706173735F75736572FF070101FF080104800000000000000000000000";
using (System.IO.MemoryStream ms = new System.IO.MemoryStream())
{
using (System.Security.Cryptography.AesManaged AES = new System.Security.Cryptography.AesManaged())
{
AES.KeySize = 128;
AES.BlockSize = 128;
AES.Key = StringToByteArray(encKey);
AES.IV = StringToByteArray("00000000000000000000000000000000");
AES.Padding = System.Security.Cryptography.PaddingMode.None;
AES.Mode = System.Security.Cryptography.CipherMode.CBC;
byte[] bytesToBeEncrypted = StringToByteArray(dataToEncrypt);
using (var cs = new System.Security.Cryptography.CryptoStream(ms, AES.CreateEncryptor(), System.Security.Cryptography.CryptoStreamMode.Write))
{
cs.Write(bytesToBeEncrypted, 0, bytesToBeEncrypted.Length);
cs.Close();
}
encryptedData = ByteArrayToString(ms.ToArray());
}
}
Console.WriteLine(encryptedData);
Console.ReadLine();
Result : 13A6DAD3119F29A8C4BF6D5BD11564E4E1A93F85B7F2AD9E8E97756688754DE32A23ADE41DFD9F76186D8EB25E66D0DCF458ECAA026F16463811C48FC814E50B10FF57FDFDB0C0761088D1AC4DDDAE749CC77FD402A2B8E005A43AEEC914E6F9
PHP Code:
$inputText = "FF01083131323233333434FF020102FF030E3230313630313230313635353032FF040C313132323333343435353636FF05083131323233333434FF060F6D6173746572706173735F75736572FF070101FF080104800000000000000000000000";
$inputKey = "0F777D55FDB154E7D8754C3C0E660A65";
$inputText = pack("H*", $inputText);
$inputKey = pack("H*", $inputKey);
$iv = "0000000000000000";
$encryptedData = openssl_encrypt($inputText, "aes-128-cbc", $inputKey, OPENSSL_RAW_DATA, $iv);
$encryptedData = implode("", unpack("H*", $encryptedData));
print $encryptedData . PHP_EOL;
Result:
99d84f4a728affe97e05b5153cb5d4842d7396cc9b26d807afd08e0f1e904a4e9f43b7d2c35151c6e609230879d120ae180c18bb461b071e79afd98ffec09e29addf9cddeaafaabf6bdef174a7781b538dd7f67e577810c261f5e6e07cb1b5be2416b80d7a59fadbf66f960968614191
I can not understand the difference of these two codes. I think they must have same output, but not.
output.

You should pack the iv :
<?php
$inputText = "FF01083131323233333434FF020102FF030E3230313630313230313635353032FF040C313132323333343435353636FF05083131323233333434FF060F6D6173746572706173735F75736572FF070101FF080104800000000000000000000000";
$inputKey = "0F777D55FDB154E7D8754C3C0E660A65";
$inputText = pack("H*", $inputText);
$inputKey = pack("H*", $inputKey);
$iv = pack("H*", "00000000000000000000000000000000");
$encryptedData = openssl_encrypt($inputText, "aes-128-cbc", $inputKey, OPENSSL_RAW_DATA, $iv);
$encryptedData = substr(implode("", unpack("H*", $encryptedData)),0,192);
print $encryptedData . PHP_EOL;

Use base64_encode($encryptedData) instead of implode.

Related

AES-128-CBC issue with PHP and C#

I have a php code code like below
$cipher = "AES-128-CBC";
$key = openssl_digest("OfVb3CjsZhnX81ZzjfAHuIiMtKEUyrt6", 'SHA256', TRUE);
$ivlen = openssl_cipher_iv_length($cipher);
$iv = openssl_random_pseudo_bytes($ivlen);
$ciphertext_raw = openssl_encrypt("wsUser", $cipher, $key, OPENSSL_RAW_DATA, $iv);
$hmac = hash_hmac('sha256', $ciphertext_raw, $key, true);
$result = base64_encode($iv . $hmac . $ciphertext_raw);
//$result value will decode by http_build_query
// $request_query["Key"] = $result;
// $last_query = http_build_query($request_query);
I converted PHPcode to C# like this ;
var cipher = "AES-128-CBC-----";
var key = SHA256.Create().ComputeHash(Encoding.UTF8.GetBytes("OfVb3CjsZhnX81ZzjfAHuIiMtKEUyrt6"));
var ivlen = cipher.Length;
byte[] iv = new byte[16]; Random rnd = new Random();
rnd.NextBytes(iv);
var aes = Aes.Create("AesManaged");
//C# 4.5
byte[] m = new byte[16];
Array.Copy(key, 0, m, 0, 16);
aes.Key = m;
//C# 8.0
aes.Key = key[0..16];
aes.IV = iv;
aes.Mode = CipherMode.CBC;
aes.Padding = PaddingMode.PKCS7;
var encryptor = aes.CreateEncryptor(aes.Key,iv);
var ciphertextRaw = encryptor.TransformFinalBlock(Encoding.UTF8.GetBytes(txtwsuser.Text), 0, txtwsuser.Text.Length); //this is "wsUser"
var hmac = new HMACSHA256(key).ComputeHash(ciphertextRaw);
string cw = Convert.ToBase64String(iv.Concat(hmac).Concat(ciphertextRaw).ToArray());
textBox1.Text = HttpUtility.UrlEncode(cw).Replace("%3d", "%3D"); //this line for debug purposes
but even though the two hashes (key value and hmac value) are the same, PHP decryptor block doesn'T work.
my PHP decryptor code block like this;
$encrypted_value = urldecode("data_from_client"); // can be used textBox1.Text value for this.
$cipher = "AES-128-CBC";
$key = openssl_digest(wsKey, 'SHA256', TRUE);
$cw = base64_decode($encrypted_value);
$ivlen = openssl_cipher_iv_length($cipher);
$iv = substr($cw, 0, $ivlen);
$hmac = substr($cw, $ivlen, $sha2len=32);
$cw3 = substr($cw, $ivlen+$sha2len);
$calcmac = hash_hmac('SHA256', $cw3, $key, true);
$result = openssl_decrypt($cw3, $cipher, $key, OPENSSL_RAW_DATA, $iv);
decrytor PHP code works with PHP code above, but C# doesn't work. I tried some AES methods but no change.How can AES-128 encryption be the same in php and C#. ?
Thanks in advance
C# code generated
sCn1%2bY2Kx9RzIiDIsWL1xWRxecMO%2bkPhIdkBfXbV6uD7%2by75f3EvwpyP4e3CHLDjBZ7U0CrVDsK4MdBUn25K0Q%3D%3D
value. PHP cannot decrypt the data. but hash values are correct.
PHP Code generated
%2FUMZJmd2LfIJzJntETKcgo%2F7VDaBV8U9iLY%2Bopq2Up5%2BrtOLRMxR%2B3OzbzgLEx0ZZErjZFP8oOtMmnZ%2FEX1dxA%3D%3D
this works fine.
After Add lines to C# Code at belows, problem solved
//C# 4.5
byte[] m = new byte[16];
Array.Copy(key, 0, m, 0, 16);
aes.Key = m;
//C# 8.0
aes.Key = key[0..16];

Finding similar code in PHP from C# code (AES-256 decryption)

I am been trying to similar pattern in PHP of following c# code . I had spent 7 days, trying to implement a simple encrypted communication in my EPin API application. The thing is, that response from the php script is giving me Blank
public static string AESDecryptText(string input, string key)
{
// Get the bytes of the string
byte[] bytesToBeDecrypted = Convert.FromBase64String(input);
byte[] keyBytes = Encoding.UTF8.GetBytes(key);
keyBytes = SHA256.Create().ComputeHash(keyBytes);
byte[] bytesDecrypted = AESDecrypt(bytesToBeDecrypted, keyBytes);
string result = Encoding.UTF8.GetString(bytesDecrypted);
return result;
}
public static byte[] AESDecrypt(byte[] bytesToBeDecrypted, byte[] keyBytes)
{
byte[] decryptedBytes = null;
// Set your salt here, change it to meet your flavor:
// The salt bytes must be at least 8 bytes.
byte[] saltBytes = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 };
using (MemoryStream ms = new MemoryStream())
{
using (RijndaelManaged AES = new RijndaelManaged())
{
AES.KeySize = 256;
AES.BlockSize = 128;
var key = new Rfc2898DeriveBytes(keyBytes, saltBytes, 1000);
AES.Key = key.GetBytes(AES.KeySize / 8);
AES.IV = key.GetBytes(AES.BlockSize / 8);
AES.Mode = CipherMode.CBC;
using (var cs = new CryptoStream(ms, AES.CreateDecryptor(), CryptoStreamMode.Write))
{
cs.Write(bytesToBeDecrypted, 0, bytesToBeDecrypted.Length);
cs.Close();
}
decryptedBytes = ms.ToArray();
}
}
return decryptedBytes;
}
MY PHP Code from other thread ..
function DecryptString($content, $password =
'4J2lh3Lz4q6ACo16VrL1oLDnh3k7G1KaXliUPVPV8o0='){
$password = mb_convert_encoding($password, "utf-16le");
$padding = 32 - (strlen($password) % 32);
$password .= str_repeat("\0", $padding);
$iv = substr($password, 0, 8);
$data = base64_decode($content);
$decrypted = openssl_decrypt($data, 'AES-256-CBC', $password,
OPENSSL_RAW_DATA, $iv);
$decrypted = mb_convert_encoding($decrypted, "utf-8", "utf-16le");
return $decrypted;
}
function decryption(){
$password = "4J2lh3Lz4q6ACo16VrL1oLDnh3k7G1KaXliUPVPV8o0=";
$content = "wKamNpehMEqJQ4NcUueNuXq1PbupsxwEvwcJ0CeI+8Q=";
echo $this->DecryptString($content, $password);
}
Every time I prints , showing empty blank. Please help on this regards
In your C# code you use SHA256 to hash the password and Rfc2898DeriveBytes to create the key and IV. The PHP analogous functions are hash (with sha256) and hash_pbkdf2.
A PHP equivalent of your C# AESDecryptText method:
function AESDecryptText($content, $password){
$password = hash('sha256', $password, true);
$salt = pack("C*",1,2,3,4,5,6,7,8);
$bytes = hash_pbkdf2("sha1", $password, $salt, 1000, 48, true);
$key = substr($bytes, 0, 32);
$iv = substr($bytes, 32, 16);
return openssl_decrypt($content, 'AES-256-CBC', $key, 0, $iv);
}
Some notes:
Salt should be unique for each password.
IV should be random and not related to the password or key.
You could use openssl_random_pseudo_bytes to create random bytes.
Salt and IV don't have to be secret, you can store them next to the ciphertext.
You should consider using HMAC to authenticate your ciphertext.
You could use hash_hmac for that purpose.

decrypt C# encrypted string in PHP

I'm trying to decrypt a string in PHP.
I use this code for encrypting the string in C#:
public string EncryptMessage(string text, string key)
{
byte[] plainTextBytes = Encoding.UTF8.GetBytes(text);
RijndaelManaged aes = new RijndaelManaged();
aes.KeySize = 256;
aes.BlockSize = 256;
aes.Padding = PaddingMode.Zeros;
aes.Mode = CipherMode.CBC;
aes.Key = Encoding.Default.GetBytes(key);
aes.GenerateIV();
string IV = ("specialstring" + Encoding.Default.GetString(aes.IV));
ICryptoTransform AESEncrypt = aes.CreateEncryptor(aes.Key, aes.IV);
byte[] buffer = plainTextBytes;
return
Convert.ToBase64String(Encoding.Default.GetBytes(Encoding.Default.GetString(AESEncrypt.TransformFinalBlock(buffer, 0, buffer.Length)) + IV));
}
I also use this code for decrypting the string in PHP:
function decrypt($text, $pkey)
{
$key = $pkey;
$text = base64_decode($text);
$IV = substr($text, strrpos($text, "specialstring") );
$text = str_replace("specialstring".$IV, "", $text);
$res = rtrim(mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $key, $text, MCRYPT_MODE_CBC, $IV), "\0");
return $res;
}
The PHP code always return empty string. Whats wrong in my code and how can I fix it?

Decrypting data encrypted with AES-256-CBC in C# as with PHP

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.

EnCrypt PHP -> C#

I would like to convert php code to c# code :
The PHP Code :
$key = "xxxxxxxxxxxx";
$message = "MY MESSAGE";
$iv_length = mcrypt_get_iv_size( MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CFB );
$iv = mcrypt_create_iv( $iv_length, MCRYPT_RAND );
$encrypted = mcrypt_encrypt( MCRYPT_RIJNDAEL_256, $key, $message, MCRYPT_MODE_CFB, $iv );
$result = base64_encode( $iv . $encrypted );
The C# Code :
public static string Encrypt(string message, string key)
{
var text = Encoding.Default.GetBytes(message);
using (var aes = new RijndaelManaged())
{
aes.BlockSize = 256;
aes.KeySize = 256;
aes.Padding = PaddingMode.Zeros;
aes.Mode = CipherMode.CFB;
aes.GenerateIV();
var encryptor = aes.CreateEncryptor(Encoding.Default.GetBytes(key), aes.IV);
using (var ms = new MemoryStream())
{
using (var cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write))
{
cs.Write(text, 0, text.Length);
cs.FlushFinalBlock();
}
var byteResult = new byte[aes.IV.Length + ms.ToArray().Length];
Buffer.BlockCopy(aes.IV, 0, byteResult, 0, aes.IV.Length);
Buffer.BlockCopy(ms.ToArray(), 0, byteResult, aes.IV.Length, ms.ToArray().Length);
return Convert.ToBase64String(byteResult);
}
}
}
But it does not work.
The encoded string from C# is not accepted by php code
Can you help me please ?
Thanks

Categories