decrypt C# encrypted string in PHP - c#

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?

Related

c# decryption from swift encryption

In swift I wrote this code to encrypt a string
func Encrypt2(_ input:String)->String?{
let key = "123456abcdefcdhs"
do{
let encrypted: Array<UInt8> = try AES(key: key, iv: key, padding: .pkcs5).encrypt(Array(input.utf8))
return encrypted.toBase64()?.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed)!
}catch{
}
return nil
}
And in c# the code for decryption is this
string key = "123456abcdefcdhs";
RijndaelManaged rijndaelCipher = new RijndaelManaged();
rijndaelCipher.Mode = CipherMode.CBC;
rijndaelCipher.Padding = PaddingMode.PKCS7;
rijndaelCipher.KeySize = 0x80;
rijndaelCipher.BlockSize = 0x80;
byte[] encryptedData = Convert.FromBase64String(textToDecrypt);
byte[] pwdBytes = Encoding.UTF8.GetBytes(key);
byte[] keyBytes = new byte[0x10];
int len = pwdBytes.Length;
if (len > keyBytes.Length)
{
len = keyBytes.Length;
}
Array.Copy(pwdBytes, keyBytes, len);
rijndaelCipher.Key = keyBytes;
rijndaelCipher.IV = keyBytes;
byte[] plainText = rijndaelCipher.CreateDecryptor().TransformFinalBlock(encryptedData, 0, encryptedData.Length);
return Encoding.UTF8.GetString(plainText);
Encrytion works fine but when it comes to c# decryption...give me an error saying
base64 length.
I tried changing the .pkcs5 to .pkcs7 but still doesn't work.
whats wrong with the code?
The base64 string is --> aMtLgvWQOguK+GPbGT/Jxw==
sometimes the string is --> aMtLgvWQOguK GPbGT/Jxw==

C# encrypt/decrypt methods which are equivalent to PHP7 openssl

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.

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.

Encrypting using C# AES encryption & decryption from these PHP codes

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.

tripledes encryption not yielding same results in PHP and C#

When I encrypt with C# I get arTdPqWOg6VppOqUD6mGITjb24+x5vJjfAufNQ4DN7rVEtpDmhFnMeJGg4n5y1BN
static void Main(string[] args)
{
Encoding byteEncoder = Encoding.Default;
String key = "ShHhd8a08JhJiho98ayslcjh";
String message = "Let us meet at 9 o'clock at the secret place.";
String encryption = Encrypt(message, key, false);
String decryption = Decrypt(encryption , key, false);
Console.WriteLine("Message: {0}", message);
Console.WriteLine("Encryption: {0}", encryption);
Console.WriteLine("Decryption: {0}", decryption);
}
public static string Encrypt(string toEncrypt, string key, bool useHashing)
{
byte[] keyArray;
byte[] toEncryptArray = UTF8Encoding.UTF8.GetBytes(toEncrypt);
if (useHashing)
{
MD5CryptoServiceProvider hashmd5 = new MD5CryptoServiceProvider();
keyArray = hashmd5.ComputeHash(UTF8Encoding.UTF8.GetBytes(key));
}
else
keyArray = UTF8Encoding.UTF8.GetBytes(key);
TripleDESCryptoServiceProvider tdes = new TripleDESCryptoServiceProvider();
tdes.Key = keyArray;
tdes.Mode = CipherMode.ECB;
tdes.Padding = PaddingMode.PKCS7;
ICryptoTransform cTransform = tdes.CreateEncryptor();
byte[] resultArray = cTransform.TransformFinalBlock(toEncryptArray, 0, toEncryptArray.Length);
return Convert.ToBase64String(resultArray, 0, resultArray.Length);
}
public static string Decrypt(string toDecrypt, string key, bool useHashing)
{
byte[] keyArray;
byte[] toEncryptArray = Convert.FromBase64String(toDecrypt);
if (useHashing)
{
MD5CryptoServiceProvider hashmd5 = new MD5CryptoServiceProvider();
keyArray = hashmd5.ComputeHash(UTF8Encoding.UTF8.GetBytes(key));
}
else
keyArray = UTF8Encoding.UTF8.GetBytes(key);
TripleDESCryptoServiceProvider tdes = new TripleDESCryptoServiceProvider();
tdes.Key = keyArray;
tdes.Mode = CipherMode.ECB;
tdes.Padding = PaddingMode.PKCS7;
ICryptoTransform cTransform = tdes.CreateDecryptor();
byte[] resultArray = cTransform.TransformFinalBlock(toEncryptArray, 0, toEncryptArray.Length);
return UTF8Encoding.UTF8.GetString(resultArray);
}
When I encrypt with PHP I get: arTdPqWOg6VppOqUD6mGITjb24+x5vJjfAufNQ4DN7rVEtpDmhFnMVM+W/WFlksR
<?php
$key = "ShHhd8a08JhJiho98ayslcjh";
$input = "Let us meet at 9 o'clock at the secret place.";
$td = mcrypt_module_open('tripledes', '', 'ecb', '');
$iv = mcrypt_create_iv (mcrypt_enc_get_iv_size($td), MCRYPT_RAND);
mcrypt_generic_init($td, $key, $iv);
$encrypted_data = mcrypt_generic($td, $input);
mcrypt_generic_deinit($td);
mcrypt_module_close($td);
echo base64_encode($encrypted_data);
?>
I don't know enough about cryptography to figure out why. Any ideas? Thanks.
Peter is right. PHP just pads with zeros, while you're using PKCS#7 in the C# code. Here's some code that should do it right:
function pkcs7_pad($text, $blocksize)
{
$pad = $blocksize - (strlen($text) % $blocksize);
return $text . str_repeat(chr($pad), $pad);
}
$input = pkcs7_pad("Let us meet at 9 o'clock at the secret place.", 16);
Alternatively, you should be able to put this in your C# code:
tdes.Padding = PaddingMode.Zeros;
and also have it work (albeit slightly less securely).
I don't know PHP, and neither have I analysed your C# code carefully, but as most of the encrypted string is the same maybe the padding of the data is the difference? Maybe PHP uses another mode than the PaddingMode.PKCS7 used in the C# code? (This would have been a comment if I could comment...)
As a side note: if you are using ECB then you do not need an IV. Actually, using ECB is most of the time a security hazard, so you really need to use something else, e.g. CBC, which uses an IV. The IV is a random, non-secret value with the same size than the cipher block size (8 bytes for 3DES). A new IV must be created for each message, and the decrypting party must know the IV that the encrypting party used. In practice, the IV is sent along with the encrypted message.

Categories