Rijndael 256 Encrypt/decrypt between c# and php? - c#

UPDATED
I have made the changes to the C# code so it uses a block size of 256. but now the hello world looks like this http://pastebin.com/5sXhMV11 and I cant figure out what I should use with rtrim() to get ride of the mess at the end.
Also when you say the IV should be random, by this do you mean don't use the same IV more then once or is the way I have coded it wrong?
Thanks again!
Hi,
I'm trying to decrypt a string with PHP that was encrypted in C#. I can't seem to get PHP to decrypt it using mcrypt and could do with some help please. I get the following error with php so I am guessing I'm not setting the IV correctly.
Error: The IV parameter must be as long as the blocksize
Both functions use the same cipher, key, IV and set to CBC mode:
encrypted text from c# = UmzUCnAzThH0nMkIuMisqg==
key 32 long = qwertyuiopasdfghjklzxcvbnmqwerty
iv 16 long = 1234567890123456
C#
public static string EncryptString(string message, string KeyString, string IVString)
{
byte[] Key = ASCIIEncoding.UTF8.GetBytes(KeyString);
byte[] IV = ASCIIEncoding.UTF8.GetBytes(IVString);
string encrypted = null;
RijndaelManaged rj = new RijndaelManaged();
rj.Key = Key;
rj.IV = IV;
rj.Mode = CipherMode.CBC;
try
{
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();
encrypted = Convert.ToBase64String(encoded);
ms.Close();
}
catch (CryptographicException e)
{
Console.WriteLine("A Cryptographic error occurred: {0}", e.Message);
return null;
}
catch (UnauthorizedAccessException e)
{
Console.WriteLine("A file error occurred: {0}", e.Message);
return null;
}
catch (Exception e)
{
Console.WriteLine("An error occurred: {0}", e.Message);
}
finally
{
rj.Clear();
}
return encrypted;
}
PHP
var $mcrypt_cipher = MCRYPT_RIJNDAEL_256;
var $mcrypt_mode = MCRYPT_MODE_CBC;
function decrypt($key, $iv, $encrypted)
{
$encrypted = base64_decode($encrypted);
$decrypted = rtrim(mcrypt_decrypt($this->mcrypt_cipher, $key, $encrypted, $this->mcrypt_mode, $iv), "\0");;
return $decrypted;
}
Thanks

If you want to use Rijndael256 in your C# application you have to set the BlockSize to 256.
RijndaelManaged rj = new RijndaelManaged();
rj.BlockSize = 256;
And then your iv has to be 256 bits long as well.
see SymmetricAlgorithm.BlockSize Property
Or the other way round: Currently your C# application uses Rijndael128 and so must your php script.
<?php
class Foo {
protected $mcrypt_cipher = MCRYPT_RIJNDAEL_128;
protected $mcrypt_mode = MCRYPT_MODE_CBC;
public function decrypt($key, $iv, $encrypted)
{
$iv_utf = mb_convert_encoding($iv, 'UTF-8');
return mcrypt_decrypt($this->mcrypt_cipher, $key, base64_decode($encrypted), $this->mcrypt_mode, $iv_utf);
}
}
$encrypted = "UmzUCnAzThH0nMkIuMisqg==";
$key = "qwertyuiopasdfghjklzxcvbnmqwerty";
$iv = "1234567890123456";
$foo = new Foo;
echo $foo->decrypt($key, $iv, $encrypted);
prints hello world

Encrypt using PHP;
/Generate public key for encrytion
$path = "keys/";
$crt = openssl_x509_read(file_get_contents($path."cert.crt"));
$publickey = openssl_get_publickey($crt);
//Encrypt using public key
openssl_public_encrypt($source, $crypted, $publickey);
//openssl_private_encrypt($source, $crypted, $privkey);
echo base64_encode($crypted);
Decrypt using C#
X509Certificate2 x509cert = new X509Certificate2(pKeyFilename);
RSACryptoServiceProvider.UseMachineKeyStore = false;
RSACryptoServiceProvider crypt = (RSACryptoServiceProvider)x509cert.PrivateKey;
byte[] decrypted = crypt.Decrypt(Convert.FromBase64String(data), false);
return ASCIIEncoding.UTF8.GetString(decrypted);
where pKeyFilename is a Personal Information Exchange File created with the certificate file cert.crt. This examples uses a AES-256 encryption.

Related

C# Encryption Information

We are using below code to encrypt/decrypt text to store some sensitive information into our database.
public static string Encrypt(string inputText)
{
const string ENCRYPTION_KEY = "MY_KEY";
byte[] SALT = Encoding.ASCII.GetBytes(ENCRYPTION_KEY.Length.ToString());
System.Security.Cryptography.RijndaelManaged rijndaelCipher = null;
byte[] plainText = null;
System.Security.Cryptography.PasswordDeriveBytes SecretKey = null;
try
{
rijndaelCipher = new System.Security.Cryptography.RijndaelManaged();
plainText = Encoding.Unicode.GetBytes(inputText);
SecretKey = new System.Security.Cryptography.PasswordDeriveBytes(ENCRYPTION_KEY, SALT);
using (System.Security.Cryptography.ICryptoTransform encryptor = rijndaelCipher.CreateEncryptor(SecretKey.GetBytes(32), SecretKey.GetBytes(16)))
{
using (System.IO.MemoryStream memoryStream = new System.IO.MemoryStream())
{
using (System.Security.Cryptography.CryptoStream cryptoStream = new System.Security.Cryptography.CryptoStream(memoryStream, encryptor, System.Security.Cryptography.CryptoStreamMode.Write))
{
cryptoStream.Write(plainText, 0, plainText.Length);
cryptoStream.FlushFinalBlock();
return Convert.ToBase64String(memoryStream.ToArray());
}
}
}
}
catch
{
throw;
}
finally
{
rijndaelCipher = null;
plainText = null;
plainText = null;
}
}
public static string Decrypt(string inputText)
{
string ENCRYPTION_KEY = "MY_KEY";
byte[] SALT = Encoding.ASCII.GetBytes(ENCRYPTION_KEY.Length.ToString());
System.Security.Cryptography.RijndaelManaged rijndaelCipher = null;
byte[] encryptedData = null;
byte[] plainText = null;
try
{
rijndaelCipher = new System.Security.Cryptography.RijndaelManaged();
encryptedData = Convert.FromBase64String(inputText);
System.Security.Cryptography.PasswordDeriveBytes secretKey = new System.Security.Cryptography.PasswordDeriveBytes(ENCRYPTION_KEY, SALT);
using (System.Security.Cryptography.ICryptoTransform decryptor = rijndaelCipher.CreateDecryptor(secretKey.GetBytes(32), secretKey.GetBytes(16)))
{
using (System.IO.MemoryStream memoryStream = new System.IO.MemoryStream(encryptedData))
{
using (System.Security.Cryptography.CryptoStream cryptoStream = new System.Security.Cryptography.CryptoStream(memoryStream, decryptor, System.Security.Cryptography.CryptoStreamMode.Read))
{
plainText = new byte[encryptedData.Length];
int decryptedCount = cryptoStream.Read(plainText, 0, plainText.Length);
return Encoding.Unicode.GetString(plainText, 0, decryptedCount);
}
}
}
}
catch
{
return "";
}
finally
{
rijndaelCipher = null;
encryptedData = null;
plainText = null;
}
}
I am not original developer who wrote this code, I need to write some documentation related to security so want to know the exact name of above algorithm. Can someone tell me what is the exact name of above methodology to encrypt/decrypt text. Like MD5, SHA256, AES etc.
I googled a lot but not able to find proper confident answer.
Thanks.
Rijndael is the algorithm that won AES competition, but only for the version with 128 bits of BlockSize. Microsoft doc states that the default value for RijndaelManaged class is 128 so this code uses AES-256-CBC with PKCS7 padding (the key is 32 bytes and no mode is specified).
However this code is very unsecure: you should use a mode such as GCM, or CBC/CTR plus a checksum, and the key should never be derivated from a simple hardcoded ascii string, no matter how long or complex it is, with the salt being a simple copy of it. Finally the IV should be random and saved along the cipherText and not derivated from the key, otherwise attacks common for ECB mode could be applied here as well.
PS: RijndaelManaged is marked as obsolete and Aes or AesCryptoServiceProvider should be used.

Decrypt AES message in OpenSSL PHP encrypted in C#

I have two applications, one writen in C#, the other in PHP.
C# application encrypt messages using AES 256 CBC. Key used for encrypt is located in a byte[] property hardcoded in the class. The Initialization vector is also hardcoded and is the same through the time.
C# Application
byte[] key = {142, 237, ....};
byte[] InitilizationVector = {132, ...};
var mensajeSinEncriptar = "";
SymmetricAlgorithm algoritmo = SymmetricAlgorithm.Create("Rijndael");
algoritmo.BlockSize = 128;
algoritmo.Mode = CipherMode.CBC;
algoritmo.Padding = PaddingMode.Zeros;
algoritmo.KeySize = 256;
algoritmo.Key = key;
algoritmo.IV = InitilizationVector;
ICryptoTransform encriptador = algoritmo.CreateEncryptor();
byte[] textoPlano = Encoding.Default.GetBytes(mensajeSinEncriptar);
MemoryStream memoryStream = new MemoryStream();
CryptoStream cryptoStream = new CryptoStream(memoryStream, encriptador, CryptoStreamMode.Write);
cryptoStream.Write(textoPlano, 0, textoPlano.Length);
cryptoStream.FlushFinalBlock();
memoryStream.Close();
cryptoStream.Close();
return Convert.ToBase64String(memoryStream.ToArray());
Then, in my PHP application I want to decrypt the messages generated by c # using OpenSSL.
I use the same key and iv used in C#. I convert them to characters because the function does not accept anything other than string.
PHP
private function decrypt(string $message)
{
$stringOf = function ($bytes) {
return implode('', array_map('chr', $bytes));
};
$key = [142, 237, ...];
$iv = [132, ... ];
$result = openssl_decrypt(
base64_decode($message),
'aes-256-cbc',
$stringOf($key),
1,
$stringOf($iv)
);
if (is_bool($result) && !$result) {
return new Error('Error: ' . openssl_error_string());
}
return $result;
}
When I try to decrypt I get this error
Error: error:06065064:digital envelope routines:EVP_DecryptFinal_ex:bad decrypt
I guess it's a mistake of mine when trying to convert the key to a string. Since I also have a function to encrypt which gives me different results using the same key and iv used in C#.

Encrypt / Decrypt data with AES between c# and PHP - decrypted data starts with 255,254

I have to request data from an external existing webservice written in C#.
This webservice requires some of the data to be encrypted (The connection uses an SSL connection, some of the data is aes encrypted)
On the php site openssl is used for decrypting.
The following settings are used on the c# site
(This are the default values for the AesCryptoServiceProvider):
Algorithm: AES
Padding: PKCS7
Mode: CBC
Keysize: 256
The padding for PKCS7 works as following:
01 If 1 byte is missing
02 02 If 2 bytes are missing
and so on
so this values are not added by the padding.
What am I doing wrong?
I've checked this with c#, php and ruby - the decrypted data starts with 255, 254
To reproduce use the following parameters:
data:1234567890123456
key: First1
salt(iv):Data
using System;
using System.Security.Cryptography;
using System.Text;
using System.IO;
namespace crypto_test
{
class MainClass
{
public static void Main(string[] args)
{
bool running = true;
while (running)
{
Console.WriteLine("Enter data:");
var data = Console.ReadLine();
Console.WriteLine("Enter key:");
var key = Console.ReadLine();
Console.WriteLine("Enter iv:");
var iv = Console.ReadLine();
Console.WriteLine("Enter d for decode");
var decode = (Console.ReadLine() == "d");
string encoded=Crypt(data, key, iv, decode);
Console.WriteLine(encoded);
if (!decode)
{
encoded= Crypt(encoded, key, iv, true);
Console.WriteLine(encoded);
}
Console.WriteLine("quit to exit");
running = !(Console.ReadLine() == "quit");
}
}
public static string Crypt(string value, string password, string salt, bool decrypt)
{
DeriveBytes rgb = new Rfc2898DeriveBytes(password, Encoding.Unicode.GetBytes(salt));
SymmetricAlgorithm algorithm = new AesCryptoServiceProvider();
byte[] rgbKey = rgb.GetBytes(algorithm.KeySize >> 3);
byte[] rgbIV = rgb.GetBytes(algorithm.BlockSize >> 3);
Console.WriteLine("rbKey: size:{0} key:{1}", (algorithm.KeySize >> 3), GetHex(rgbKey));
Console.WriteLine("rgbIV: size:{0} key:{1}", (algorithm.BlockSize >> 3), GetHex(rgbIV));
ICryptoTransform transform = decrypt ? algorithm.CreateDecryptor(rgbKey, rgbIV) : algorithm.CreateEncryptor(rgbKey, rgbIV);
Console.WriteLine("Mode {0}", algorithm.Mode);
Console.WriteLine("PAdding {0}", algorithm.Padding);
using (MemoryStream buffer = new MemoryStream())
{
using (CryptoStream stream = new CryptoStream(buffer, transform, CryptoStreamMode.Write))
{
try
{
if (decrypt)
{
byte[] data = Convert.FromBase64String(value);
stream.Write(data,0,data.Length);
}
else
{
using (StreamWriter writer = new StreamWriter(stream, Encoding.Unicode))
{
writer.Write(value);
}
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
byte[] buff = buffer.ToArray();
if (decrypt)
{
return Encoding.Unicode.GetString(buff) + "\r\n" + GetHex(buff);
}
else
return Convert.ToBase64String(buff);
}
}
public static string GetHex(byte[] data)
{
StringBuilder sb = new StringBuilder();
for (int i = 0; i < data.Length; ++i)
sb.Append(data[i].ToString("X2"));
return sb.ToString();
}
}
}
I have not found an equivalent to Rfc2898DeriveBytes until now,
so I copied the key and iv
php
<?php
$salt='Data';
$pass='First1';
$data='1234567890123456';
$encrypted_base64='VKNd9Pi+cttaM6ne8pzAuFbH1U0gJiJ2Wlbbr1rU5z8vbIfAS6nb0/5py4p54aK7';
$encrypted=base64_decode($encrypted_base64);
$key = pack('H*', "30EE7F95F0EF4835F048A481424F2F52EE21B7CEB97F8CC437E5949DB53797D9");
$iv = pack('H*', "B29F5ECF7057065758102385509F0637");
$cipher='AES-256-CBC';
$decrypted = openssl_decrypt($encrypted,$cipher, $key,true,$iv);
for($i =0; $i<strlen($decrypted);++$i)
{
echo "char:" . ord($decrypted[$i])."<br/>";
}
echo $decrypted
?>
ruby:
require ('openssl')
require ('base64')
while true
enc_data='VKNd9Pi+cttaM6ne8pzAuFbH1U0gJiJ2Wlbbr1rU5z8vbIfAS6nb0/5py4p54aK7'
data = Base64.decode64(enc_data)
key_hex='30EE7F95F0EF4835F048A481424F2F52EE21B7CEB97F8CC437E5949DB53797D9'
iv_hex='B29F5ECF7057065758102385509F0637'
key = [key_hex].pack('H*')
iv = [iv_hex].pack('H*')
decipher = OpenSSL::Cipher::AES.new(256, :CBC)
decipher.decrypt
decipher.key = key
decipher.iv = iv
plain = decipher.update(data) + decipher.final
puts plain
puts plain.bytes
end
Good news, your decryption seems to work OK.
What you are seeing in the decrypted ciphertext is the byte order mark for UTF-16 LE, which is (incorrectly) indicated by Microsoft as Encoding.Unicode. You need to do either one off two things:
decode the text with a decoder that groks UTF-16 LE including byte order mark;
encode using much more reasonable UTF-8 encoding (in the C# code).
Personally I would put a strong preference on (2).

Encrypting and decrypting very long strings with AES 256 C# php

I got an encrypting function written in PHP which encrypts my data, and a decrypt function in C# which decrypts it and prints on screen(I'm developing a game in Unity engine). So the problem is, if the data string is long it won't decrypt the last part of it... I'm using AES 256 encryption with key
php function:
$username = "Name"
$id = 1;
$email = "email#example.com"
$data = $username . "\n" . $id . "\n" . $email;
$key = "my 256 bit key"; //32 bytes
function aes256Encrypt($key, $data) {
if(32 !== strlen($key)) $key = hash('SHA256', $key, true);
$padding = 16 - (strlen($data) % 16);
$data .= str_repeat(chr($padding), $padding);
return mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $data, MCRYPT_MODE_CBC, str_repeat("\0", 16));
}
echo base64_encode(aes256Encrypt($key, $data));
This is my C# full code which prints the decrypted string on game screen:
using UnityEngine;
using System.Collections;
using System;
using System.IO;
using System.Text;
using System.Security.Cryptography;
public class session : MonoBehaviour {
private string sessionURL = "http://localhost/xampp/game/session.php";
void Start ()
{
StartCoroutine(GetSession());
}
IEnumerator GetSession()
{
gameObject.guiText.text = "Loading Session";
WWW ses_get = new WWW(sessionURL);
yield return ses_get;
string key = "my 256 bit key";
string base64_ciphered_text = ses_get.text;
String sestext = Decrypt(base64_ciphered_text, key);
if (ses_get.error != null)
{
print("There was an error getting the session: " + ses_get.error);
}
else
{
guiText.richText = true;
guiText.text = sestext;
}
}
public String Decrypt(String text, String key)
{
//decode cipher text from base64
byte[] cipher = Convert.FromBase64String(text);
//get key bytes
byte[] btkey = Encoding.ASCII.GetBytes(key);
//init AES 256
RijndaelManaged aes256 = new RijndaelManaged();
aes256.Mode = CipherMode.ECB;
aes256.Padding = PaddingMode.Zeros;
//decrypt
ICryptoTransform decryptor = aes256.CreateDecryptor(btkey, null);
MemoryStream ms = new MemoryStream(cipher);
CryptoStream cs = new CryptoStream(ms, decryptor, CryptoStreamMode.Read);
byte[] plain = new byte[cipher.Length];
int decryptcount = cs.Read(plain, 0, plain.Length);
ms.Close();
cs.Close();
//return plaintext in String
return Encoding.UTF8.GetString(plain, 0, decryptcount);
}
}
Anyone got an idea?
One example of what I mean:
$data: http://puu.sh/6BkU4.png
output on screen: http://puu.sh/6BkTF.jpg
You're using CBC-mode in PHP and ECB in C# so after the first block things will go wrong. You need to use the same mode in both cases.

How to decrypt an AES-256-CBC encrypted string

I'm new to C# and I really need help. I need to encrypt/decrypt a string with AES-256-CBC in C#, I found this to encrypt a string:
public static string EncryptString(string message, string KeyString, string IVString)
{
byte[] Key = ASCIIEncoding.UTF8.GetBytes(KeyString);
byte[] IV = ASCIIEncoding.UTF8.GetBytes(IVString);
string encrypted = null;
RijndaelManaged rj = new RijndaelManaged();
rj.Key = Key;
rj.IV = IV;
rj.Mode = CipherMode.CBC;
try
{
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();
encrypted = Convert.ToBase64String(encoded);
ms.Close();
}
catch (CryptographicException e)
{
Console.WriteLine("A Cryptographic error occurred: {0}", e.Message);
return null;
}
catch (UnauthorizedAccessException e)
{
Console.WriteLine("A file error occurred: {0}", e.Message);
return null;
}
catch (Exception e)
{
Console.WriteLine("An error occurred: {0}", e.Message);
}
finally
{
rj.Clear();
}
return encrypted;
}
I tried to write a decrypt function base on the above code, the following code is what I did:
// Decrypt a byte array into a byte array using a key and an IV
private byte[] Decrypt(byte[] cipherData, byte[] Key, byte[] IV)
{
byte[] decryptedData;
//string plaintext = null;
//MemoryStream ms = new MemoryStream(cipherData);
RijndaelManaged alg = new RijndaelManaged();
alg.KeySize = 256;
alg.BlockSize = 128;
alg.Key = Key;
alg.IV = IV;
alg.Mode = CipherMode.CBC;
alg.Padding = PaddingMode.Zeros;
//Array.Copy(Key, 0, IV, 0, IV.Length);
ICryptoTransform decryptor = alg.CreateDecryptor(alg.Key, alg.IV);
using(MemoryStream ms = new MemoryStream(cipherData))
{
using (CryptoStream csDecrypt = new CryptoStream(ms, decryptor, CryptoStreamMode.Read))
{
using (StreamReader sw = new StreamReader(csDecrypt))
{
sw.ReadToEnd();
sw.Close();
}
csDecrypt.Close();
decryptedData = ms.ToArray();
}
}
//byte[] decryptedData = System.Text.Encoding.Unicode.GetBytes(plaintext);
return decryptedData;
}
But it's nonsense, it can't decrypt anything. I'm really confused and need help. Thank you for any help!
P/s: Please don't give me other similar answered questions, I already take a look at them. Their encrypt function doesn't have the same output like the above encrypt function, while I need to decrypt string which MUST be encrypt by the above function. I have two friend who wrote decrypt function in PHP and objective-C, which matched with the above encrypt function, it's bad to have them do it again.
Looking at your encryption, something like this should do it, passing the resulting string from your encryption in should give the original string back;
// Decrypt a string into a string using a key and an IV
public static string Decrypt(string cipherData, string keyString, string ivString)
{
byte[] key = Encoding.UTF8.GetBytes(keyString);
byte[] iv = Encoding.UTF8.GetBytes(ivString);
try
{
using (var rijndaelManaged =
new RijndaelManaged {Key = key, IV = iv, Mode = CipherMode.CBC})
using (var memoryStream =
new MemoryStream(Convert.FromBase64String(cipherData)))
using (var cryptoStream =
new CryptoStream(memoryStream,
rijndaelManaged.CreateDecryptor(key, iv),
CryptoStreamMode.Read))
{
return new StreamReader(cryptoStream).ReadToEnd();
}
}
catch (CryptographicException e)
{
Console.WriteLine("A Cryptographic error occurred: {0}", e.Message);
return null;
}
// You may want to catch more exceptions here...
}
A small note; you're getting the key using UTF8 encoding from the key string, UTF8 encoding may give you multiple bytes back for international characters, which may give a key or IV of the wrong length for encryption/decryption. Also, using the small range of passwords/keys with 8 characters and printable characters will not give you very secure encryption, you may want to run the string though SHA1 or similar before using it as a key (which will sadly make it incompatible with the current encryption)

Categories