I have taken the decrypt code from http://msdn.microsoft.com/en-us/library/system.security.cryptography.cryptostream.aspx and modified it as follows below. I have an encrypted example, and it works just fine while decoding. But when using the encryption function, it returns junk string with strange symbols. below are the functions of encrypt/decrypt.
An example of encrypted string "hey" : "???U?b???z?Y???"
When decoded again: "ûc{ÁpÅ`ñ""Â"
I'm using this code to convert the byte array to string:
private string ByteArrayToString(byte[] input)
{
ASCIIEncoding dec = new ASCIIEncoding();
return dec.GetString(input);
}
here are the encrypt/decrypt functions. the decryption function is working fine.
private string DecryptStringFromBytesAes(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");
// Declare the string used to hold
// the decrypted text.
string plaintext = null;
// Create an RijndaelManaged object
// with the specified key and IV.
using (RijndaelManaged aesAlg = new RijndaelManaged())
{
aesAlg.Key = Key;
aesAlg.Padding = PaddingMode.Zeros;
aesAlg.Mode = CipherMode.ECB;
// Create a decrytor to perform the stream transform.
ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.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;
}
private byte[] EncryptStringToBytesAes(string plainText, byte[] Key, byte[] IV)
{
// Check arguments.
if (plainText == null || plainText.Length <= 0)
throw new ArgumentNullException("plainText");
if (Key == null || Key.Length <= 0)
throw new ArgumentNullException("Key");
byte[] encrypted;
// Create an RijndaelManaged object
// with the specified key and IV.
using (RijndaelManaged aesAlg = new RijndaelManaged())
{
aesAlg.Key = Key;
aesAlg.Padding = PaddingMode.Zeros;
aesAlg.Mode = CipherMode.ECB;
// Create a decrytor to perform the stream transform.
ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV);
// Create the streams used for encryption.
using (MemoryStream msEncrypt = new MemoryStream())
{
using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
{
using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
{
//Write all data to the stream.
swEncrypt.Write(plainText);
}
encrypted = msEncrypt.ToArray();
}
}
}
return encrypted;
}
What you observe is the problem of mapping arbitrary bytes (in the range 0-255) to characters. Meaningful characters are only in the range 32-255 or even only 32-127 (ASCII). Values below 32 are the so-called non-printable characters and values above 127 are dependent on the character encoding you are using. That's why the crypted text looks like junk. Mast crypto-systems therefore transform the bytes into the sensible ASCII-range. One such algorithm is BASE64. So mangling the crypted bytes through BASE64 gives characters that are all printable and that will go without problems through e-mail. Before decrypting you then have to undo the BASE64 encoding.
Another way to make the encrypted result look better is to show the hexa-decimal representation of it. For example if you have a byte value of 15 you print 0F. You may use this to represent your byte array in hex:
private string ByteArrayToHexString(byte[] data)
{
return String.Concat(data.Select(b => b.ToString("x2")));
}
In order to have your output as a hexadecimal encoding of the data, follow the methods found here. I modified them slightly to be extension methods:
public static string ToHexString(this byte[] bytes)
{
return bytes == null ? string.Empty : BitConverter.ToString(bytes).Replace("-", string.Empty);
}
public static byte[] FromHexString(this string hexString)
{
if (hexString == null)
{
return new byte[0];
}
var numberChars = hexString.Length;
var bytes = new byte[numberChars / 2];
for (var i = 0; i < numberChars; i += 2)
{
bytes[i / 2] = Convert.ToByte(hexString.Substring(i, 2), 16);
}
return bytes;
}
Encrypted strings will look like garble. The way to test if the encryption is working correctly is to pass your string back through decrypt. If it works at decrypting then you know the string is correct despite looking like garbage to you.
Related
I'm actually trying to make a secure file transfer program
and I would like to encrypt the sent file with the c# Aes.Create() method
but I wanted a AES-256 encryption and I'm not sure that the method does a 256 bits key
so I searched on Microsoft docs and many sketchy websites but I did find nothing.
So, how many bits generate Aes.Create()?
There is my code:
using System.Security.Cryptography;
namespace ConsoleApp1
{
internal class Program
{
public static void Main()
{
string original = File.ReadAllText(#"C:\SomePath");
// Create a new instance of the Aes
// class. This generates a new key and initialization
// vector (IV).
using (Aes myAes = Aes.Create())
{
// Encrypt the string to an array of bytes.
byte[] encrypted = EncryptStringToBytes_Aes(original, myAes.Key, myAes.IV);
// Decrypt the bytes to a string.
string roundtrip = DecryptStringFromBytes_Aes(encrypted, myAes.Key, myAes.IV);
//Display the original data and the decrypted data.
Console.WriteLine("Original: {0}", original);
Console.WriteLine("Encrypted: {0}", System.Text.Encoding.Default.GetString(encrypted));
Console.WriteLine("Round Trip: {0}", roundtrip);
}
}
static byte[] EncryptStringToBytes_Aes(string plainText, byte[] Key, byte[] IV)
{
// Check arguments.
if (plainText == null || plainText.Length <= 0)
throw new ArgumentNullException("plainText");
if (Key == null || Key.Length <= 0)
throw new ArgumentNullException("Key");
if (IV == null || IV.Length <= 0)
throw new ArgumentNullException("IV");
byte[] encrypted;
// Create an Aes object
// with the specified key and IV.
using (Aes aesAlg = Aes.Create())
{
aesAlg.Key = Key;
aesAlg.IV = IV;
// Create an encryptor to perform the stream transform.
ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV);
// Create the streams used for encryption.
using (MemoryStream msEncrypt = new MemoryStream())
{
using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
{
using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
{
//Write all data to the stream.
swEncrypt.Write(plainText);
}
encrypted = msEncrypt.ToArray();
}
}
}
// Return the encrypted bytes from the memory stream.
return encrypted;
}
static string DecryptStringFromBytes_Aes(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("IV");
// Declare the string used to hold
// the decrypted text.
string? plaintext = null;
// Create an Aes object
// with the specified key and IV.
using (Aes aesAlg = Aes.Create())
{
aesAlg.Key = Key;
aesAlg.IV = IV;
// Create a decryptor to perform the stream transform.
ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.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;
}
}
}
Yes, it's a modified version of Microsoft docs on Aes class: https://learn.microsoft.com/en-us/dotnet/api/system.security.cryptography.aes
AES is a block cipher. That means it encrypts a fixed-sized block of clear text bytes into a same-sized block of cipher text bytes (hence the term block cipher). AES uses 128-bit blocks, i.e. 16 bytes long. This is irrespective of key size.
To be able to encrypt data of an arbitrary length, block ciphers use different modes of operation. Depending on the mode, padding is applied, an initialization vector may be used, salt prepended, and dependencies between blocks are employed.
Hence, as a result, the total size of encrypted data may be slightly bigger than the original size of the unencrypted data. The difference accounts for (at least) the length of the initialization vector and/or salt and any padding to the nearest multiple of the cipher's block size.
I am currently working on AES implementation in C#. The encryption method has two parameters: a string and a password. I am taking the supplied string and converting it to an array of bytes, so I can use it later for writing data to a stream with BinaryWriter.
The problem is that when I use Convert.FromBase64String(string) I get FormatException: Invalid length.and when I use Encoding.UTF8.GetBytes(string) my decryption method throws and invalid PKCS7.Padding exception.
I have been trying to solve this problem for the last couple of days. I have read near infinite questions in stackoverflow.com and other websites, but I still don't know what is the most reliable way to solve this problem.
Strings that will be used in this program are limited to sentences (ex. "Something to encrypt.") and numbers (ex. "12345").
Thank you in advance, here is the code I have at this point in time:
public class AESProvider {
public byte[] EncryptStringToBytes_Aes(string plainText, string Key)
{
// Check arguments.
if (plainText == null || plainText.Length <= 0)
throw new ArgumentNullException("plainText");
if (Key == null || Key.Length <= 0)
throw new ArgumentNullException("Key");
byte[] plainTextInBytes = Convert.FromBase64String(plainText);
byte[] encrypted;
//Create an Aes object
//with the specified key and IV.
using (Aes aesAlg = Aes.Create())
{
aesAlg.GenerateIV();
byte[] IV = aesAlg.IV;
//The Salt will be the first 8 bytes of the IV.
byte[] theSalt = new byte[8];
Array.Copy(IV,theSalt,8);
//A key for AES is generated by expanding the password using the following method.
Rfc2898DeriveBytes keyGen = new Rfc2898DeriveBytes(Key,theSalt);
byte[] aesKey = keyGen.GetBytes(16);
aesAlg.Key = aesKey;
// Create a decrytor to perform the stream transform.
ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, IV);
// Create the streams used for encryption.
using (MemoryStream msEncrypt = new MemoryStream())
{
using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
{
using (BinaryWriter swEncrypt = new BinaryWriter(csEncrypt))
{
//Write all data to the stream.
swEncrypt.Write(plainTextInBytes);
}
encrypted = msEncrypt.ToArray();
}
}
// Prepend the IV to the ciphertext so it can be used in the decryption process.
using (MemoryStream ivPlusCipher = new MemoryStream())
{
using (BinaryWriter tBinaryWriter = new BinaryWriter(ivPlusCipher))
{
tBinaryWriter.Write(IV);
tBinaryWriter.Write(encrypted);
tBinaryWriter.Flush();
}
return ivPlusCipher.ToArray();
}
}
}
public byte[] DecryptStringFromBytes_Aes(byte[] cipherText, string Key)
{
// Check arguments.
if (cipherText == null || cipherText.Length <= 0)
throw new ArgumentNullException("cipherText");
if (Key == null || Key.Length <= 0)
throw new ArgumentNullException("Key");
// Declare the string used to hold
// the decrypted text.
byte[] decrypted;
// Create an Aes object
// with the specified key and IV.
// Create the streams used for decryption.
using (Aes aesAlg = Aes.Create())
{
aesAlg.Mode = CipherMode.CBC;
aesAlg.Padding = PaddingMode.PKCS7;
//Grab IV from ciphertext
byte[] IV = new byte[16];
Array.Copy(cipherText,0,IV,0,16);
//Use the IV for the Salt
byte[] theSalt = new byte[8];
Array.Copy(IV,theSalt,8);
Rfc2898DeriveBytes keyGen = new Rfc2898DeriveBytes(Key,theSalt);
byte[] aesKey = keyGen.GetBytes(16);
aesAlg.Key = aesKey;
// Create a decrytor to perform the stream transform.
ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, IV);
using (MemoryStream msDecrypt = new MemoryStream())
{
using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Write))
{
using (BinaryWriter srDecrypt = new BinaryWriter(csDecrypt))
{
//Decrypt the ciphertext
srDecrypt.Write(cipherText, IV.Length, (cipherText.Length - IV.Length));
}
decrypted = msDecrypt.ToArray();
return decrypted;
}
}
}
}
}
You need to convert between bytes and strings before and after encryption/decryption. This is not the same operation, and you should not use the same method.
When encrypting you start out with an arbitrary string. Convert this to a byte[] using Encoding.UTF8.GetBytes(). Encrypt it. The resulting byte[] can now be converted to a string using Convert.ToBase64String().
When decrypting you now start out with a Base64 encoded string. Decode this to a byte[] using Convert.FromBase64String(). Decrypt it. You now have the UTF-8 encoding of your original string, which you can decode using Encoding.UTF8.GetString().
Remember:
Encoding.UTF8 works to convert arbitrary strings to byte-arrays (but it can only convert byte-arrays that contain actual UTF8-encodings back).
Convert.[To/From]Base64String works to convert arbitrary byte-arrays to strings (but it can only convert strings that contain actual Base64-encodings back).
Looking at your lines
public byte[] EncryptStringToBytes_Aes(string plainText, string Key)
byte[] plainTextInBytes = Convert.FromBase64String(plainText);
Arbitrary plain text will not be a base 64 encoded string. Even if it is supposed to be base 64 encoded text, your error message indicates that the length is not divisible by 4
FormatException
The length of s, ignoring white-space characters, is not zero or a multiple of 4.
-or-
The format of s is invalid. s contains a non-base-64 character, more than two padding characters, or a > non-white space-character among the padding characters.
http://msdn.microsoft.com/en-us/library/system.convert.frombase64string(v=vs.110).aspx
If it is a base 64 encoded string, you need to pad it accorgingly
http://en.wikipedia.org/wiki/Base64
Convert.FromBase64String(string); is expected to receive a string generated by Convert.ToBase64String(byte[]); passing in a arbitrary string will not work.
The easiest solution is replace the BinaryWriter and BinaryReader with a StreamWriter and a StreamReader and not do any conversion at all.
public byte[] EncryptStringToBytes_Aes(string plainText, string Key)
{
// Check arguments.
if (plainText == null || plainText.Length <= 0)
throw new ArgumentNullException("plainText");
if (Key == null || Key.Length <= 0)
throw new ArgumentNullException("Key");
//Create an Aes object
//with the specified key and IV.
using (Aes aesAlg = Aes.Create())
{
aesAlg.GenerateIV();
byte[] IV = aesAlg.IV;
//The Salt will be the first 8 bytes of the IV.
byte[] theSalt = new byte[8];
Array.Copy(IV,theSalt,8);
//A key for AES is generated by expanding the password using the following method.
Rfc2898DeriveBytes keyGen = new Rfc2898DeriveBytes(Key,theSalt);
byte[] aesKey = keyGen.GetBytes(16);
aesAlg.Key = aesKey;
// Create a decrytor to perform the stream transform.
ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, IV);
// Create the streams used for encryption.
using (MemoryStream msEncrypt = new MemoryStream())
{
//You can write the IV here and not need to do it later.
msEncrypt.Write(IV, 0, IV.Length);
using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
{
using (StreamWriter swEncrypt = new StreamWriter (csEncrypt))
{
//Write all data to the stream.
swEncrypt.Write(plainText);
}
}
//Move this outside of the using statement for CryptoStream so it is flushed and dipsoed.
return msEncrypt.ToArray();
}
}
}
Also, your decryption function is actually trying to encrypt the text a 2nd time, you need to pass the byte array in to the constructor of msDecrypt and put it in decryption mode.
public string DecryptStringFromBytes_Aes(byte[] cipherText, string Key)
{
// Check arguments.
if (cipherText == null || cipherText.Length <= 0)
throw new ArgumentNullException("cipherText");
if (Key == null || Key.Length <= 0)
throw new ArgumentNullException("Key");
// Create an Aes object
// with the specified key and IV.
// Create the streams used for decryption.
using (Aes aesAlg = Aes.Create())
{
aesAlg.Mode = CipherMode.CBC;
aesAlg.Padding = PaddingMode.PKCS7;
//Grab IV from ciphertext
byte[] IV = new byte[16];
Array.Copy(cipherText,0,IV,0,16);
//Use the IV for the Salt
byte[] theSalt = new byte[8];
Array.Copy(IV,theSalt,8);
Rfc2898DeriveBytes keyGen = new Rfc2898DeriveBytes(Key,theSalt);
byte[] aesKey = keyGen.GetBytes(16);
aesAlg.Key = aesKey;
// Create a decrytor to perform the stream transform.
ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, IV);
//You can chain using statements like this to make the code easier to read.
using (MemoryStream msDecrypt = new MemoryStream(cipherText))
using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read)) //Notice this is Read mode not Write mode.
using (StreamReader srDecrypt = new StreamReader(csDecrypt))
{
//Decrypt the ciphertext
return srDecrypt.ReadToEnd();
}
}
}
There may be other errors with your code, but at least this gets you on the right track.
I am Learning C#, and are practicing with decryption and encryption.
I used the Aes Class Example from MSDN, and the encryption is working great.
However, when i am trying to decrypt the textfile, nothing happens.
I figured i had done something wrong in the decryption function, so i tested with a string instead.
The decryption worked perfect with the string So i am wondering what i am doing wrong.
This is what my encryption and decryption looks like:
//The encryption
string path = #"C:\encrypt.txt";
//The path where my .txt file is.
string textfile = File.ReadAllText(path);
//Reading the text in the file and storing it in a string.
byte[] ByteToEncrypt = EncryptStringToBytes(textfile, myAes.Key, myAes.IV);
//From The Aes class example
string encrypted = "";
//Creating a string to store the bytes in.
for (int i = 0; i < ByteToEncrypt.Length; i++)
{
encrypted = encrypted + ByteToEncrypt[i];
//Adding all the bytes from an array to string.
}
File.WriteAllText(path, encrypted, LATIN1);
//Writing the encrypted string to the .txtfile.
//The decryption
string decrypted = DecryptStringFromBytes(ByteToEncrypt, myAes.Key, myAes.IV);
//From the Aes class example.
File.WriteAllText(path, Decrypted, LATIN1);
//Writing the decrypted string to textfile.
I am posting the Aes class below for further information.
static byte[] EncryptStringToBytes(string plaintext, byte[] Key, byte[] IV)
{
//Checking the arguments
if (string.IsNullOrEmpty(plaintext))
{
throw new ArgumentNullException("plaintext");
}
else if (Key == null || Key.Length <= 0)
{
throw new ArgumentNullException("key");
}
else if (IV == null || IV.Length <= 0)
{
throw new ArgumentNullException("IV");
}
byte[] encrypted;
//Create an Aes object
//With the specified key and IV
using (Aes Aesalg = Aes.Create())
{
Aesalg.Key = Key;
Aesalg.IV = IV;
//Create a encryptor to perform the stream transform
ICryptoTransform encryptor = Aesalg.CreateEncryptor(Aesalg.Key, Aesalg.IV);
//Create the streams used for encryption
using (MemoryStream msencrypt = new MemoryStream())
{
using (CryptoStream csEncrypt = new CryptoStream(msencrypt, encryptor, CryptoStreamMode.Write))
{
using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
{
swEncrypt.Write(plaintext);
}
encrypted = msencrypt.ToArray();
}
}
}
return encrypted;
}
static string DecryptStringFromBytes(byte[] ciphertext, byte[] Key, byte[] IV)
{
if (ciphertext == null || ciphertext.Length <= 0)
{
throw new ArgumentNullException("plaintext");
}
else if (Key == null || Key.Length <= 0)
{
throw new ArgumentNullException("Key");
}
else if (IV == null || IV.Length <= 0)
{
throw new ArgumentNullException("IV");
}
string plaintext = null;
using (Aes Aesalg = Aes.Create())
{
Aesalg.Key = Key;
Aesalg.IV = IV;
ICryptoTransform decryptor = Aesalg.CreateDecryptor(Aesalg.Key, Aesalg.IV);
using (MemoryStream msDecrypt = new MemoryStream(ciphertext))
{
using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
{
using (StreamReader srDecrypt = new StreamReader(csDecrypt))
{
plaintext = srDecrypt.ReadToEnd();
}
}
}
}
return plaintext;
}
You cannot just add bytes to a String. Byte can have any value between 00 and FF inclusive (using hexadecimal representation). You simply seem to add those bytes as integers to the string, as
encrypted = encrypted + ByteToEncrypt[i];
simply creates a String value such as "0255" for byte values 00 and FF. Of course, you will have an issue when you try and decrypt such a string, if only because the bytes are not separated anymore.
Instead, you should create a base 64 encoding of the ciphertext after encryption, and convert it back into bytes before decrypting. Or, as ntoskrnl suggests, you can of course just treat the ciphertext as binary all the way, if that's an option.
I'm trying to get two services to talk but I need to encrypt the message sent between them. It's early days so I'm hard coding the key, but here is what I have so far.
In c#
byte[] key = Convert.FromBase64String("QM3M8+Zbw5VYa70xtftksHHqM1UGmhOBjqOP82UtuAA=");
byte[] hexiv = Convert.FromBase64String("wRt00heBiu86mWSfuHmSag==");
using (RijndaelManaged myRijndael = new RijndaelManaged())
{
byte[] encrypted = EncryptStringToBytes(name, myRijndael.Key, myRijndael.IV);
string enc = Convert.ToBase64String(encrypted);
}
.....
static byte[] EncryptStringToBytes(string plainText, byte[] Key, byte[] IV)
{
// Check arguments.
if (plainText == null || plainText.Length <= 0)
throw new ArgumentNullException("plainText");
if (Key == null || Key.Length <= 0)
throw new ArgumentNullException("Key");
if (IV == null || IV.Length <= 0)
throw new ArgumentNullException("Key");
byte[] encrypted;
// Create an RijndaelManaged object
// with the specified key and IV.
using (RijndaelManaged rijAlg = new RijndaelManaged())
{
rijAlg.Key = Key;
rijAlg.IV = IV;
// Create a decrytor to perform the stream transform.
ICryptoTransform encryptor = rijAlg.CreateEncryptor(rijAlg.Key, rijAlg.IV);
// Create the streams used for encryption.
using (MemoryStream msEncrypt = new MemoryStream())
{
using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
{
using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
{
//Write all data to the stream.
swEncrypt.Write(plainText);
}
encrypted = msEncrypt.ToArray();
}
}
}
This outputs my message as +CPJqIL6RhIHc5+u2Nvonw==
Then in PHP, I have the following:
$key = "Zbw5VYa70xtftksHHqM1UGmhOBjqOP82UtuAA=";
$hexiv = "wRt00heBiu86mWSfuHmSag==";
$string = base64_decode("+CPJqIL6RhIHc5+u2Nvonw==");
$cipher_alg = MCRYPT_RIJNDAEL_256;
$decrypted_string = mcrypt_decrypt($cipher_alg, $key, $string , MCRYPT_MODE_CBC, $hexiv);
echo $decrypted_string."<BR>";
But this is giving me Qˆ–⤻?/P¸Üu:·ey+–Uñ :,yL±M
Hopefully the answer is fairly obvious but I can't see it.
You fell for the mcrypt trap.
MCRYPT_RIJNDAEL_256 isn't AES-256, it's the 256-bit block size variant of Rijndael. AES is always a 128-bit block size even with 256-bit keys.
Look into libsodium instead. There are bindings for .NET and PHP. If you upgrade to PHP 7.2 or higher, you should have it installed already.
I use the function EncryptStringToBytes to encrypt plain text to array of bytes and
finally convert array of bytes to string and return it then.
I use another function to Decrypt Encrypted text to plaint text.
I try to scramble a text with RC2 but it raises this error:
Rijndael class to encrypt and then decrypt data
Here's the code:
using System;
using System.IO;
using System.Text;
using System.Security.Cryptography;
namespace RC2CryptoServiceProvider_Examples
{
class MyMainClass
{
static string EncryptStringToBytes(string plainText, byte[] Key, byte[] IV)
{
// Check arguments.
if (plainText == null || plainText.Length <= 0)
throw new ArgumentNullException("plainText");
if (Key == null || Key.Length <= 0)
throw new ArgumentNullException("Key");
if (IV == null || IV.Length <= 0)
throw new ArgumentNullException("Key");
byte[] encrypted;
// Create an Rijndael object
// with the specified key and IV.
using (Rijndael rijAlg = Rijndael.Create())
{
rijAlg.Key = Key;
rijAlg.IV = IV;
// Create a decrytor to perform the stream transform.
ICryptoTransform encryptor = rijAlg.CreateEncryptor(rijAlg.Key, rijAlg.IV);
// Create the streams used for encryption.
using (MemoryStream msEncrypt = new MemoryStream())
{
using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
{
using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
{
//Write all data to the stream.
swEncrypt.Write(plainText);
}
encrypted = msEncrypt.ToArray();
}
}
}
**// Return the encrypted bytes from the memory stream.
return System.Text.Encoding.UTF8.GetString(encrypted);**
}
static string DecryptStringFromBytes(string Codedtext, byte[] Key, byte[] IV)
{
byte[] cipherText = System.Text.Encoding.UTF8.GetBytes(Codedtext);
// 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 Rijndael object
// with the specified key and IV.
using (Rijndael rijAlg = Rijndael.Create())
{
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;
}
public static void Main()
{
try
{
System.Text.UTF8Encoding enc = new System.Text.UTF8Encoding();
string original = "Here is some data to encrypt!";
// Create a new instance of the Rijndael
// class. This generates a new key and initialization
// vector (IV).
using (Rijndael myRijndael = Rijndael.Create())
{
// Encrypt the string to an array of bytes.
string encrypted = EncryptStringToBytes(original, myRijndael.Key, myRijndael.IV);
// Decrypt the bytes to a string.
string roundtrip = DecryptStringFromBytes(encrypted, myRijndael.Key, myRijndael.IV);
//Display the original data and the decrypted data.
Console.WriteLine("Original: {0}", original);
Console.WriteLine("Round Trip: {0}", roundtrip);
}
}
catch (Exception e)
{
Console.WriteLine("Error: {0}", e.Message);
}
Console.ReadLine();
}
}
}
This is the problem (or at least a problem):
return System.Text.Encoding.UTF8.GetString(encrypted);
The encrypted data isn't UTF-8 text. It's arbitrary binary data. Don't treat it as if it were encoded text.
If you really need to pass arbitrary binary data around as a string, use Base64:
return Convert.ToBase64String(encrypted);
Then in DecryptStringFromBytes, you'd use:
byte[] cipherText = Convert.FromBase64String(codedText);
(Parameter name changed to comply with conventions.)