PHP C# MCRYPT_RIJNDAEL_128 - c#

I try to do encrypt (with MCRYPT_RIJNDAEL_128 Cipher CBC) in PHP and C#, but the output does not match.
key = '1234567812345678';
iv = '1234567812345678';
PHP:
function Encrypt($data, $key, $iv) {
return base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, base64_encode($data), MCRYPT_MODE_CBC, $iv));
}
C#:
public static string Encrypt(string plainText, string key, string iv)
{
byte[] initVectorBytes = Encoding.ASCII.GetBytes(iv);
byte[] plainTextBytes = Encoding.ASCII.GetBytes(plainText);
byte[] keyBytes = Encoding.ASCII.GetBytes(key);
using (RijndaelManaged symmetricKey = new RijndaelManaged())
{
symmetricKey.Mode = CipherMode.CBC;
symmetricKey.Padding = PaddingMode.Zeros;
symmetricKey.KeySize = 128;
symmetricKey.BlockSize = 128;
using (ICryptoTransform encryptor = symmetricKey.CreateEncryptor(keyBytes, initVectorBytes))
{
using (MemoryStream memoryStream = new MemoryStream())
{
using (CryptoStream cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write))
{
cryptoStream.Write(plainTextBytes, 0, plainTextBytes.Length);
cryptoStream.FlushFinalBlock();
byte[] cipherTextBytes = memoryStream.ToArray();
return Convert.ToBase64String(cipherTextBytes);
}
}
}
}
}
Help appreciated.

I think your problems lies within your PHP code.
The mcrypt_encrypt function expects the data (which needs to be encoded) to be in plaintext format, so you don't need an additional base64_encode since you are working with strings. The same way you pass the key and the iv to the function, you should hand your data variable to it. (untested)
function Encrypt($data, $key, $iv) {
return base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $data, MCRYPT_MODE_CBC, $iv));
}
Let me know your progress, so that I can help you with this in the future if anything doesn't work :)

Related

How do I decrypt in php something aes encrypted with c#

A partner is using c# to encrypt 12 digit numbers to a database, I need to decode these values on a unix server ideally using php 5.6 but php 7.2, perl 5.16 or python 3.6 are all available.
I've started with example 2 of the php openssl-encrypt manual which gets me something which will encode/decode test strings successfully, but cannot decode the c# encoded data.
I've also tried the suggestions at https://odan.github.io/2017/08/10/aes-256-encryption-and-decryption-in-php-and-csharp.html without success, presumably because the partner isn't using CBC.
Substituting $key = substr(hash('sha256', $secret, true), 0, 32); for the secret in the function calls didn't help.
I've tried all the ciphers supported by openssl-encrypt without success.
The partner has provided their c# code (which appears to be a more or less direct lift from Microsoft sample code):
public static string EncryptString(string key, string plainText)
{
byte[] iv = new byte[16];
byte[] array;
using (Aes aes = Aes.Create())
{
aes.Key = Encoding.UTF8.GetBytes(key);
aes.IV = iv;
ICryptoTransform encryptor = aes.CreateEncryptor(aes.Key, aes.IV);
using (MemoryStream memoryStream = new MemoryStream())
{
using (CryptoStream cryptoStream = new CryptoStream((Stream)memoryStream, encryptor, CryptoStreamMode.Write))
{
using (StreamWriter streamWriter = new StreamWriter((Stream)cryptoStream))
{
streamWriter.Write(plainText);
}
array = memoryStream.ToArray();
}
}
}
return Convert.ToBase64String(array);
}
public static string DecryptString(string key, string cipherText)
{
byte[] iv = new byte[16];
byte[] buffer = Convert.FromBase64String(cipherText);
using (Aes aes = Aes.Create())
{
aes.Key = Encoding.UTF8.GetBytes(key);
aes.IV = iv;
ICryptoTransform decryptor = aes.CreateDecryptor(aes.Key, aes.IV);
using (MemoryStream memoryStream = new MemoryStream(buffer))
{
using (CryptoStream cryptoStream = new CryptoStream((Stream)memoryStream, decryptor, CryptoStreamMode.Read))
{
using (StreamReader streamReader = new StreamReader((Stream)cryptoStream))
{
return streamReader.ReadToEnd();
}
}
}
}
}
I have the following functions at present:
function encrypt2($data, $secret, $cipher, $iv)
{
$ivlen = openssl_cipher_iv_length($cipher);
$ciphertext_raw = openssl_encrypt($data, $cipher, $secret, $options=OPENSSL_RAW_DATA, $iv);
$hmac = hash_hmac('sha256', $ciphertext_raw, $secret, $as_binary=true);
return base64_encode($ciphertext_raw);
}
function decrypt2($data, $secret, $cipher, $iv)
{
$c = base64_decode($data);
$ivlen = openssl_cipher_iv_length($cipher);
$original_plaintext = openssl_decrypt($c, $cipher, $secret, $options=OPENSSL_RAW_DATA, $iv);
return ($original_plaintext ? $original_plaintext : 'openssl_decrypt failed');
}
I can't share partner data because I only have real data but here is an example call to the php functions above the second of which produces results resembling the real data:
$data = '123456789012';
$secret = "qwertyuiop12345";
$cipher = "AES-256-ECB";
$iv = "";
$encrypted2 = encrypt2($data, $secret, $cipher, $iv);
$decrypted2 = decrypt2($encrypted2, $secret, $cipher, $iv);
echo "$data > $encrypted2 > $decrypted2\n";
Gives:
123456789012 > NDdefqxcYZvtjAcvPrQ00A== > 123456789012
What changes do I need to make to my php to match the c# code?
Alternatively a solution using perl or python would work.
Update with sample data:
xyz#gmail.com encrypted with b14ca5898a4e4133bbce2ea2315a1916 gives c4Eej4S8G3mclVQJb+qkfQ==
That's exactly what my code generates.
The live key I've been given is 16 characters long but the example above uses a 32 character string, is something being done to double the length of the original before use?

Convert PHP Encryption algorithm to C#

I am trying to use a SSO solution in C#, where the documentation is only available in PHP.
I have this PHP Code:
function encrypt ($message)
{
$initialVector = "1234567890123456";
$key = md5($this->apiPassword);
$crypt = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $message, MCRYPT_MODE_CFB, $initialVector);
return base64_encode($initialVector) .":" . base64_encode($crypt);
}
The C# Code I tried is the following:
private string encrypt(string message)
{
RijndaelManaged aes128 = new RijndaelManaged();
aes128.BlockSize = 128;
aes128.KeySize = 128;
aes128.Mode = CipherMode.CFB;
aes128.Padding = PaddingMode.None;
aes128.IV = Encoding.ASCII.GetBytes("1234567890123456");
aes128.Key = Encoding.ASCII.GetBytes(getMd5(key));
byte[] plainTextBytes = Encoding.ASCII.GetBytes(json);
ICryptoTransform encryptor = aes128.CreateEncryptor();
MemoryStream ms = new MemoryStream();
CryptoStream cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write);
cs.Write(plainTextBytes, 0, plainTextBytes.Length);
// convert our encrypted data from a memory stream into a byte array.
byte[] cypherTextBytes = ms.ToArray();
// close memory stream
ms.Close();
return Convert.ToBase64String(aes128.IV) + ":" + Convert.ToBase64String(cypherTextBytes);
}
key and message are identical. The IV part is returned correctly, only the encrypted parts are not equal. The md5 method is also working correctly.
Edit: Changing the Padding also doesn't change anything.

c# Decrypt data which stored in sql server

In ms SQL server, I have a field text with data look like below:
"!"$$$$$$!#$$$$!!!!! !!!!!!!!!!!!!! "!! ! " !" ! !" !!!! ! !!"!".
I belive that from a plain text string, they using a Rijndael algorithm to encrypted this string. from encrypted string, it was transform to string above.
Can anyone recognize what the algorithm to decrypt from string above to the encrypted string of Rijndael algorithm?
thanks
Hi me drona please find the below code. It will useful from you.
public static class Encrypt
{
// This size of the IV (in bytes) must = (keysize / 8). Default keysize is 256, so the IV must be
// 32 bytes long. Using a 16 character string here gives us 32 bytes when converted to a byte array.
private const string initVector = "pemgail9uzpgzl88";
// This constant is used to determine the keysize of the encryption algorithm
private const int keysize = 256;
//Encrypt
public static string EncryptString(string plainText, string passPhrase)
{
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);
}
//Decrypt
public static string DecryptString(string cipherText, string passPhrase)
{
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);
}
enter code here

Padding is invalid and cannot be removed with Rijndael

when i use this code to encrypt and decrypt i got an error said
Padding is invalid and cannot be removed.
any idea
public static class Crypto
{
private static readonly byte[] initVectorBytes = Encoding.ASCII.GetBytes("tu89geji340t89u2");
// 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)
{
byte[] plainTextBytes = Encoding.UTF8.GetBytes(plainText);
using (PasswordDeriveBytes password = new PasswordDeriveBytes(passPhrase, null))
{
byte[] keyBytes = password.GetBytes(keysize / 8);
using (RijndaelManaged symmetricKey = new RijndaelManaged())
{
symmetricKey.Mode = CipherMode.CBC;
using (ICryptoTransform encryptor = symmetricKey.CreateEncryptor(keyBytes, initVectorBytes))
{
using (MemoryStream memoryStream = new MemoryStream())
{
using (CryptoStream cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write))
{
cryptoStream.Write(plainTextBytes, 0, plainTextBytes.Length);
cryptoStream.FlushFinalBlock();
byte[] cipherTextBytes = memoryStream.ToArray();
return Convert.ToBase64String(cipherTextBytes);
}
}
}
}
}
}
public static string Decrypt(string cipherText, string passPhrase)
{
byte[] cipherTextBytes = Convert.FromBase64String(cipherText);
using (PasswordDeriveBytes password = new PasswordDeriveBytes(passPhrase, null))
{
byte[] keyBytes = password.GetBytes(keysize / 8);
using (RijndaelManaged symmetricKey = new RijndaelManaged())
{
symmetricKey.Mode = CipherMode.CBC;
using (ICryptoTransform decryptor = symmetricKey.CreateDecryptor(keyBytes, initVectorBytes))
{
using (MemoryStream memoryStream = new MemoryStream(cipherTextBytes))
{
using (CryptoStream cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read))
{
byte[] plainTextBytes = new byte[cipherTextBytes.Length];
int decryptedByteCount = cryptoStream.Read(plainTextBytes, 0, plainTextBytes.Length);
return Encoding.UTF8.GetString(plainTextBytes, 0, decryptedByteCount);
}
}
}
}
}
}
}
I tried the following using your methods and it worked fine:
var passPhrase = "123456";
var e = Encrypt("testtesttesttest", passPhrase);
Console.WriteLine(e); // YEtSJshcn686ZO+JlEQ48ap/odhuvIGalbAT1XhinqQ=
var d = Decrypt(e, passPhrase);
Console.WriteLine(d); // testtesttesttest
This suggests that you're either passing a different passPhrase to Decrypt() to the one you passed to Encrypt(), or that you are somehow corrupting the ciphertext prior to decryption. (Are you perhaps calling Decrypt with the ciphertext and passphrase parameters reversed?)
It's also worth noting that essentially everything in the comments at the top of your code is wrong:
You're not passing any salt to PasswordDeriveBytes.
The size of the IV must be equal to the block size (16 bytes), it is unrelated to the key size used.
Passing a 16 character string through Encoding.ASCII.GetBytes() results in a 16 byte output, not 32 bytes. (This rather coincidentally means that your initVectorBytes is in fact the correct length for the IV).
Furthermore, PasswordDeriveBytes is deprecated and should not be used. You should be using Rfc2898DeriveBytes instead, and you should be using a proper salt value. The IV should also not be a static value, and definitely not one derived from an ASCII string!

Encrypting with AES

Why can I encrypt only 16 characters of text?
Works:
string plainText = "1234567890123456";
Doesn't work:
string plainText = "12345678901234561";
Doesn't work:
string plainText = "123456789012345";
Code:
string plainText = "1234567890123456";
byte[] plainTextBytes = Encoding.UTF8.GetBytes(plainText);
byte[] keyBytes = System.Text.Encoding.UTF8.GetBytes("1234567890123456");
byte[] initVectorBytes = System.Text.Encoding.UTF8.GetBytes("1234567890123456");
RijndaelManaged symmetricKey = new RijndaelManaged();
symmetricKey.Mode = CipherMode.CBC;
symmetricKey.Padding = PaddingMode.Zeros;
ICryptoTransform encryptor = symmetricKey.CreateDecryptor(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();
string cipherText = Convert.ToBase64String(cipherTextBytes);
Console.ReadLine();
Not sure I understand the question, but looking at what I assume the intent is of the code the following
symmetricKey.CreateDecryptor
Should probably be
symmetricKey.CreateEncryptor
Probably because AES is a block cipher with 128 bits per block.. maybe you just need to add a padding such that length % 128 == 0.
(I'm not a C# developer but it can happen that an implementation doesn't care about adding padding by itself)
Just a hint: try if it works with 256 bits

Categories

Resources