Rijndael encrypter: Getting empty byte[]. Not encrypting anything - c#

Good evening!
I'm trying to implement an encrypter using Rijndael algorithm and Rijndael class in c#. I tried to follow (not doing exactly the same code) the link bellow, but the problem is given a string to be encrypted I'm not getting any result. I'm no getting any error message too.
https://learn.microsoft.com/pt-br/dotnet/api/system.security.cryptography.rijndael?view=netframework-4.8
CryptDecrypt.cs
using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;
namespace RijndaelAlgorithm {
public class CryptDecrypt {
private Byte[] iv;
private Byte[] key;
public CryptDecrypt(String key) {
iv = new Byte[] {21, 10, 21, 251, 132, 76, 121, 27, 210, 81, 215, 99, 14, 235, 11, 75};
this.key = Encoding.ASCII.GetBytes(key);
}
public String encryptMsg(String originalMsg) {
byte[] encryptedMsg;
Rijndael rijAlg = Rijndael.Create();
rijAlg.Key = formatKey();
rijAlg.IV = iv;
MemoryStream msEncrypt = new MemoryStream();
ICryptoTransform encryptor = rijAlg.CreateEncryptor(rijAlg.Key, rijAlg.IV);
CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write);
StreamWriter swEncrypt = new StreamWriter(csEncrypt);
swEncrypt.Write(originalMsg);
encryptedMsg = msEncrypt.ToArray();
Console.WriteLine("encryptedMsg.Length: " + encryptedMsg.Length);
return Convert.ToBase64String(encryptedMsg, 0, encryptedMsg.Length);
}
private Byte[] formatKey() {
int len = key.Length;
String strKey = System.Text.Encoding.UTF8.GetString(key);
String fillKey = "";
String strFormatedKey = "";
Byte[] formatedKeyByte;
if (len < 16)
fillKey = new String('X',(16 - len));
strFormatedKey = String.Concat(strKey, fillKey);
formatedKeyByte = Encoding.ASCII.GetBytes(strFormatedKey);
return formatedKeyByte;
}
}
}
Menu.cs
using System;
namespace RijndaelAlgorithm {
public class Menu {
private CryptDecrypt r;
public Menu() {
r = new CryptDecrypt("123654");
}
public void showMenu() {
Console.WriteLine("the encrypted message is: " + r.encryptMsg("isjustatest"));
}
}
}

You seem to want to encrypt a message with your .NET application and want to get the same encrypted bytes as a particular online service that you mention in one of your comments.
Parameter
One parameter for an encryption is the initialization vector (IV). It should be random and used only once. So if two apps are correctly implemented (with different random IVs), the encrypted bytes are different.
This service returns a different result every time you press the key, even if you use the same input.
However, if you generally take the different encrypted results and decrypt them with the same key, you will get the original bytes back.
The next problem with testing with this specific service is, that they delivering always the same prefix base64 sequence 'U2FsdGVkX1'. This is not standard AES output (if you decode this base64 sequence you get 'Salted_P'). So it makes sense to use a different online service for tests.
So if two AES-256 encoding implementations are using the same parameters, we will get the same encoded result. We need for it:
Key (32 bytes, not 16 for AES-256)
IV (16 bytes)
Speaking of key length: As others mentioned in the comments, you should not simply add "X" or something similar, but use a standard cryptographic mechanism to derive a good key.
Convenient for tests are methods that convert hex strings to byte arrays and back, e.g. see StringToByteArray and ByteArrayToString methods in this cool answer:
https://stackoverflow.com/a/311179
Let's give it a try. If we take your message 'isjustatest' which has the hex string'69736a7573746174657374374', we need a 32-byte key for AES-256 and 16 bytes IV.
As others mentioned in the comments, you need to flush and close the stream (or better yet, use a 'using' statement).
Taking your code and change the key and iv assignment and output the encrypted message to the console:
rijAlg.Key = StringToByteArray("519C7C3402A943D8AF83746C1548E475319EBDA6A38046059F83B21709BD6A5B"); //32 bytes
rijAlg.IV = StringToByteArray("0D024CF947CE4C288880D0B34D29BFA5"); // 16 bytes
...
swEncrypt.Write(originalMsg);
swEncrypt.Flush();
swEncrypt.Close();
...
Console.WriteLine("encrypted bytes: '" + ByteArrayToString(encryptedMsg) + "'");
This results in the output of '419536f27da3406625b2d07f43833aab' in the debug console.
So now we can use an online service, e.g. https://cryptii.com/pipes/aes-encryption where we can enter input data, select the encryption algorithm, supply key and IV bytes and then we get the same result as in your program, see screenshot here:
As mentioned above, don't forget to use different random IVs when using it in a real application.

Related

AES decryption only producing part of the answer C#

I'm trying to learn cyber security and this is the very first thing I've done on it. I'm using this MSDN document ( https://learn.microsoft.com/en-us/dotnet/api/system.security.cryptography.rfc2898derivebytes?redirectedfrom=MSDN&view=netcore-3.1 ) and it partly works. I assume it's encrypting it fine as when it comes to the decryption some of the original data is there but some is lost. The data that is being encrypted is a class that has been formatted into a JSON string( I don't think this is relevant as it's still a string being encrypted).
But once it's been encrypted and decrypted it turns out like this:
I've ran this code and compared the results 5+ times and it's always: the start is wrong, username is partly right, password is always right and loginkey is partly right. So the error is recurring and always in the same spot.
Information you should know, the data get's encrypted and saved to a .txt file. The programme will run again and it will try and decrypted it. The Salt and password are saved on another file and those are read and used in the decryption.
There is a similar question on stackoverflow but the answer just says to use Rijndael(so not really an answer), this code is for me to learn and want an answer that isn't 4 lines long.
Code if curious(but it's basically the same as the MSDN document):
Encryption:
static void EncryptFile()
{
string pwd1 = SteamID;//steamID is referring to account ID on Valve Steam
using (RNGCryptoServiceProvider rngCsp = new
RNGCryptoServiceProvider())
{
rngCsp.GetBytes(salt1); //salt1 is a programme variable and will get saved to a file
}
SecureData File = new SecureData(_UserName,_PassWord,_LoginKey);
string JsonFile = JsonConvert.SerializeObject(File); //puts the class into Json format
int myIterations = 1000; //not needed
try
{
Rfc2898DeriveBytes k1 = new Rfc2898DeriveBytes(pwd1, salt1,
myIterations);
Aes encAlg = Aes.Create(); // This might be the issue as AES will be different when you decrypt
encAlg.Key = k1.GetBytes(16);
MemoryStream encryptionStream = new MemoryStream();
CryptoStream encrypt = new CryptoStream(encryptionStream,
encAlg.CreateEncryptor(), CryptoStreamMode.Write);
byte[] utfD1 = new System.Text.UTF8Encoding(false).GetBytes(
JsonFile); //encrypt Data
encrypt.Write(utfD1, 0, utfD1.Length);
encrypt.FlushFinalBlock();
encrypt.Close();
byte[] edata1 = encryptionStream.ToArray();
k1.Reset();
System.IO.File.WriteAllBytes(SecureFile, edata1); //writes encrypted data to file
}
catch (Exception e)
{
Console.WriteLine("Error: ", e);
}
}
Decryption:
static void DecryptFile()
{
string pwd1 = SteamID;
byte[] edata1;
try
{
edata1 = System.IO.File.ReadAllBytes(SecureFile); //reads the file with encrypted data on it
Aes encAlg = Aes.Create(); //I think this is the problem as the keyvalue changes when you create a new programme
Rfc2898DeriveBytes k2 = new Rfc2898DeriveBytes(pwd1, salt1); //inputs from last time carry over
Aes decAlg = Aes.Create();
decAlg.Key = k2.GetBytes(16);
decAlg.IV = encAlg.IV;
MemoryStream decryptionStreamBacking = new MemoryStream();
CryptoStream decrypt = new CryptoStream(
decryptionStreamBacking, decAlg.CreateDecryptor(), CryptoStreamMode.Write);
decrypt.Write(edata1, 0, edata1.Length);
decrypt.Flush();
decrypt.Close();
k2.Reset();
string data2 = new UTF8Encoding(false).GetString(
decryptionStreamBacking.ToArray());//decrypted data
SecureData items = JsonConvert.DeserializeObject<SecureData>(data2); //reformat it out of JSon(Crashes as format isn't accepted)
_UserName = items.S_UserName;
_PassWord = items.S_Password;
_LoginKey = items.S_LoginKey;
}
catch (Exception e)
{
Console.WriteLine("Error: ", e);
NewLogin();
}
}
Class Struct:
class SecureData
{
public string S_UserName { get; set; } //These are variables that are apart of Valve steam Login process
public string S_Password { get; set; }
public string S_LoginKey { get; set; }
public SecureData(string z, string x, string y)
{
S_UserName = z;
S_Password = x;
S_LoginKey = y;
}
}
The problem is caused by different IVs for encryption and decryption. For a successful decryption the IV from the encryption must be used.
Why are different IVs applied? When an AES instance is created, a random IV is implicitly generated. Two different AES instances therefore mean two different IVs. In the posted code, different AES instances are used for encryption and decryption. Although the reference encAlg used in the decryption has the same name as that of the encryption, the referenced instance is a different one (namely an instance newly created during decryption). This is different in the Microsoft example. There, the IV of the encryption is used in the decryption: decAlg.IV = encAlg.IV, where encAlg is the AES instance with which the encryption was performed.
The solution is to store the IV from the encryption in the file so that it can be used in the decryption. The IV is not secret and is usually placed before the ciphertext:
Necessary changes in EncryptFile:
...
byte[] utfD1 = new System.Text.UTF8Encoding(false).GetBytes(JsonFile);
encryptionStream.Write(encAlg.IV, 0, encAlg.IV.Length); // Write the IV
encryptionStream.Flush();
encrypt.Write(utfD1, 0, utfD1.Length);
...
Necessary changes in DecryptFile:
...
edata1 = System.IO.File.ReadAllBytes(SecureFile);
byte[] iv = new byte[16]; // Separate IV and ciphertext
byte[] ciphertext = new byte[edata1.Length - iv.Length];
Array.Copy(edata1, 0, iv, 0, iv.Length);
Array.Copy(edata1, iv.Length, ciphertext, 0, ciphertext.Length);
...
Aes encAlg = Aes.Create(); // Remove this line
...
decAlg.IV = iv; // Use the separated IV
...
decrypt.Write(ciphertext, 0, ciphertext.Length); // Use the separated ciphertext
A few remarks:
For each encryption a new, random salt should be generated and concatenated with the ciphertext analogous to the IV. During decryption, the salt can then be determined analogous to IV. Consider additionally RFC8018, sec 4.1.
The iteration count slows down the derivation of the key, which should make an attack by repeated attempts more difficult. Therefore the value should be as large as possible. Consider additionally RFC8018, sec 4.2.
Authentication data (i.e. passwords) are not encrypted, but hashed, here.

Converting code from PasswordDerivedBytes to Rfc2898DerivedBytes, unicode

I'm attempting to replace PasswordDerivedBytes with Rfc2898DerivedBytes but I'm having a problem with the latter when getting back a unicode encoded result.
Take this code for example:
[TestMethod]
public void DerivedBytesTest()
{
string encrypted = "y4Ijqo9Ga/mHlFbLHDdDUkYZlyu7CHF4PVXGLnb8by7FAVtCgPLhFSiA9Et6hDac";
string key = "{00B3403A-3C29-4f26-A9CC-14C411EA8547}";
string salt = "gT5M07XB9hHl3l1s";
string expected = "4552065703414505";
string decrypted;
decrypted = Decrypt(encrypted, key, salt, true);
Assert.IsTrue(decrypted == expected); // Works
decrypted = Decrypt(encrypted, key, salt, false);
Assert.IsTrue(decrypted == expected); // Doesn't work, get wrong unicode characters in 24 character string
}
private string Decrypt(string encrypted, string key, string salt, bool legacy = false)
{
UnicodeEncoding encoding = new UnicodeEncoding();
byte[] encryptedDataBytes = Convert.FromBase64String(encrypted);
byte[] saltBytes = encoding.GetBytes(salt);
RijndaelManaged encryption = new RijndaelManaged();
DeriveBytes secretKey;
if (legacy)
{
secretKey = new PasswordDeriveBytes(key, saltBytes) {IterationCount = 100};
encryption.Padding = PaddingMode.PKCS7;
}
else
{
secretKey = new Rfc2898DeriveBytes(key, saltBytes, 100);
encryption.Padding = PaddingMode.Zeros; // This is the only one that doesn't throw the "Padding is invalid and cannot be removed" exception, but gives me a non-ASCII result
}
ICryptoTransform decryptor = encryption.CreateDecryptor(secretKey.GetBytes(32), secretKey.GetBytes(16));
string decryptedText = "";
using (MemoryStream memoryStream = new MemoryStream(encryptedDataBytes))
{
using (CryptoStream cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read))
{
byte[] bytes = new byte[encryptedDataBytes.Length];
int decryptedCount = cryptoStream.Read(bytes, 0, bytes.Length);
decryptedText = encoding.GetString(bytes, 0, decryptedCount);
if (!legacy)
{
// Something more to do with result?
}
}
}
return decryptedText;
}
I wonder if anyone can advise where I'm going wrong?
PasswordDeriveBytes is a badly implemented extension of PBKDF1, while Rfc2898DeriveBytes is the implementation of PBKDF2. Both derive a key from a password, but they are two different algorithms and therefore they derive two different results. As they are using cryptographically secure hashes underneath, there is no way to convert one to another.
If you can spare a few bytes of storage you could still derive the key using PKBDF1 and then encrypt that key using the result of PBKDF2. If the output size is identical you could even use XOR encryption for that (a one-time-pad) but AES would of course also work. So then the decryption becomes: calculate PBKDF2 result, decrypt data key, use data key to decrypt ciphertext.
Otherwise you will have to decrypt and then re-encrypt the result.
If you want to compare the decryption result then compare the resulting bytes; do not first convert it into a string. Using authenticated encryption or a MAC is highly advised so that a authentication tag can be validated instead. Just ignoring padding exceptions by using Zero Padding is not the way to go. These padding errors occur because the key is wrong.
Generic notes:
PasswordDeriveBytes should not be used for any amount of bytes > 20 bytes as the Mickeysoft extension of PBKDF1 is horribly insecure, even repeating bytes in the output (!). If you do the same for PBKDF2 then any adversary will have to do half the work that you have to do so that's not a good idea either.
The iteration count in the question is very low, but as you seem to use a highly random UID instead of a password that should be OK.

How to decrypt a word which have more than 16 letters in Rijndael encryption

I made a Encryption program using Rijndael in C# after watching a video in youtube.It's very simple.
Interface picture
I can enter 64 bit and 128 bit keys. but 192 bit keys are not allowed (Why? ).
And if I use 64 bit key, when I encrypt a word and try to decrypt it back it only decrypts word with character count <= 16. it the character count is more than 16 an error messages thrown saysing "Padding is Invalid and cannot be removed".
Same goes for a 128 bit key. Only word with character count <=32 is decrypted back. otherwise same error message is displayed.
Here's a summery to take a clear view of the question
Problem Summery picture
Here's the code for Encryption
// need using System.Security.Cryptography;
// using System.IO;
public Form1()
{
InitializeComponent();
desObj = Rijndael.Create();
}
string cipherData;
byte[] chipherbytes;
byte[] plainbyte;
byte[] plainbyte2;
byte[] plainkey;
SymmetricAlgorithm desObj;
private void button2_Click(object sender, EventArgs e)
{
try
{
cipherData = textBox1.Text;
plainbyte = Encoding.ASCII.GetBytes(cipherData);
plainkey = Encoding.ASCII.GetBytes(textBox4.Text);
desObj.Key = plainkey;
//choose any method
desObj.Mode = CipherMode.CBC;
desObj.Padding = PaddingMode.PKCS7;
MemoryStream ms = new MemoryStream();
CryptoStream cs = new CryptoStream(ms, desObj.CreateEncryptor(), CryptoStreamMode.Write);
cs.Write(plainbyte, 0, plainbyte.Length);
cs.Close();
chipherbytes = ms.ToArray();
ms.Close();
textBox2.Text = Encoding.ASCII.GetString(chipherbytes);
}
catch(Exception ex)
{
MessageBox.Show(ex.Message);
}
}
and the decyption code is
private void button3_Click(object sender, EventArgs e)
{
try
{
MemoryStream ms1 = new MemoryStream(chipherbytes);
CryptoStream cs1 = new CryptoStream(ms1, desObj.CreateDecryptor(), CryptoStreamMode.Read);
cs1.Read(chipherbytes, 0, chipherbytes.Length);
plainbyte2 = ms1.ToArray();
cs1.Close();
ms1.Close();
textBox3.Text = Encoding.ASCII.GetString(plainbyte2);
}
catch(Exception ex)
{
MessageBox.Show(ex.Message);
}
}
Ciphertext consists of arbitrary bytes which do not have to make up a valid ASCII encoding. If there are some non-printable ASCII characters, they will not be printed when used in this way: Encoding.ASCII.GetString(chipherbytes).
You need to encode the ciphertext with something like Base64 or Hex which will make the encoded ciphertext larger, but is perfectly representable as a printed string.
Other considerations:
CBC mode needs an initialization vector (IV) and since you're not setting any IV, it will be generated for you. The problem is that you need the same IV during decryption. This code works, because you're using the same desObj for encryption and decryption and it contains the same IV, but that's not going to work when you start copying ciphertext around.
The IV is not supposed to be secret. A common way is to pass it along with the ciphertext by writing the IV in front of it and slicing it off before decryption.
You're not having any integrity checking. It is better to authenticate your ciphertexts so that attacks like a padding oracle attack are not possible and you can detect whether the ciphertext was (maliciously) tampered with or the key was typed in incorrectly. This can be done with authenticated modes like GCM or EAX, or with an encrypt-then-MAC scheme.
Rijndael commonly supports key sizes of 128, 192 and 256 bit. A byte usually has 8 bits, so that amounts to 16, 24 and 32 byte keys.
Keys are not typed in by the user, because they usually need to be indistinguishable from random noise and of specific length. It is better to let users type in a password and derive the key from that with something like PBKDF2, bcrypt, scrypt or Argon2 using a high iteration count / cost factor.

Add salt to data to be encrypted?

Suppose a small amount of data is being encrypted with AES using a 256 key / IV. The data encrypted could be known. For example:
abcdefghijklmno|axXXyyYY343433553353afsafaadfafdfsafsf|2013-01-01T00:00:00
The first two parts (if you break the data on the pipe character) rarely change. the last part, a date / time does change but not often. I've noticed that varying the date but not the first part of the message results in a cypher text which starts out the same all the time, presumably because the plain text is the same to start off.
Does this open me up to any kind of attacks against the encryption algorithm? Would I gain anything by prepending a salt value to the beginning of the plain text?
I'm using the AesManaged class to generate the IV / Key and encrypt / decrypt the plain text, if that makes a difference.
To solve this problem, normally the IV is generated randomly for each cypertext and prepended not encrypted to the encrypted data. In this way every encrypted data is different from the others.
In code it should be
string str = "abcdefghijklmno|axXXyyYY343433553353afsafaadfafdfsafsf|2013-01-01T00:00:00";
byte[] data = Encoding.UTF8.GetBytes(str);
byte[] key = new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }; // Your random key, I hope more random!
byte[] encrypted;
// Encrypt
using (var am = new AesManaged())
using (var rng = new RNGCryptoServiceProvider())
{
am.Key = key;
var iv = new byte[am.BlockSize / 8];
rng.GetBytes(iv);
am.IV = iv;
using (var encryptor = am.CreateEncryptor())
using (var ms = new MemoryStream())
{
ms.Write(iv, 0, iv.Length);
using (var encStream = new CryptoStream(ms, encryptor, CryptoStreamMode.Write))
{
encStream.Write(data, 0, data.Length);
}
encrypted = ms.ToArray();
}
}
// Decrypt
string str2;
using (var am = new AesManaged())
using (var ms = new MemoryStream(encrypted))
{
am.Key = key;
var iv = new byte[am.BlockSize / 8];
ms.Read(iv, 0, iv.Length);
am.IV = iv;
using (var decryptor = am.CreateDecryptor())
using (var decStream = new CryptoStream(ms, decryptor, CryptoStreamMode.Read))
using (var ms2 = new MemoryStream())
{
decStream.CopyTo(ms2);
str2 = Encoding.UTF8.GetString(ms2.GetBuffer(), 0, (int)ms2.Length);
}
}
Note that in general IV reuse cause a weakness in encryption. See for example the wiki:
For CBC and CFB, reusing an IV leaks some information about the first block of plaintext, and about any common prefix shared by the two messages. For OFB and CTR, reusing an IV completely destroys security.[6]
This is one of the primary purposes of the IV. You should generate a random IV for each message that you send (if you're already doing that, something must be wrong in your code).
AES256 should mix data in blocks of 256 bits (32 bytes). Since you have a long leading text (>32 bytes) that rarely changes you will have poor performance using encryption method. You can fix this but beginning the plaintext string with something that changes frequently as long as it changes within the first 32 bytes. You can do this be creating some random seed and actual useful data.
The purpose of seeding is so that "known" strings will not generate recognizable patterns once encrypted. This is the exact problem you will have, so you need to seed you data or at least use volatile data near the beginning of your plaintext.
EDIT:
I saw I had a negatives and wondered why. First, by performance I was intending to refer to the quality of the encryption, not execution time. And I accidentally said seed when I meant salt. A minor mistakes, but I see why the negatives. I am leaving my answer because it is the only once that explains (or at attempts to explain) that the salt (or at least something) that changes frequently really needs to appear with the 32 bytes plaintext block fed to AES-256. Salting is usually required if your encrypted data is subject to dictionary attacks (such as passwords), which seem unlikely for the OP, but your encrypted data should never be "predictable", which is why the OP should salt with data within the first 32 bytes.

AES _Encryption in Mysql , Decryption in C#.Net

Mysql :
SELECT AES_ENCRYPT('Test','pass')
AES_ENCRYPT() and AES_DECRYPT() enable encryption and decryption of data using the official AES (Advanced Encryption Standard) algorithm, previously known as “Rijndael.” Encoding with a 128-bit key length is used, but you can extend it up to 256 bits by modifying the source. We chose 128 bits because it is much faster and it is secure enough for most purposes.
http://dev.mysql.com/doc/refman/5.5/en/encryption-functions.html#function_aes-encrypt
I was trying to convert that Encrypted string into Decryped Strig in C#.net but i don't get the results as i expect.
http://msdn.microsoft.com/en-us/library/system.security.cryptography.rijndael.aspx#Y0
C#
static string DecryptStringFromBytes(byte[] cipherText, byte[] Key, byte[] IV)
In this method I pass ciphertext,Key value which i usedfrom Mysql and
Rijndael.Create().IV for byte[] IV
I use the code but i don't get expected result.
Review the code and comment Idk where made a mistake
What you are doing is following a road of pain. Either decrypt/encrypt on MySQL and use an encrypted connection to the database (if that matters) or encrypt/decrypt on your .NET application, storing the encrypted data in a suitable column.
Mixing AES implementations is prone to mistakes and things can break more easily if you change versions of .NET or MySQL.
Now, to know what exactly is wrong we need to know if the IV is compatible between MySQL and .NET, or else find out what is MySQL's implementation IV and supply that.
And the other potential source of problems is how you have generated the byte arrays (we are not seeing that in your example). You have to consider character encoding issues in generating the arrays if the key is textual.
In the comments of this MySQL docs link there is information about the missing parameters.
After a long hours, I found a solution to this issue.
Couple of FYI's:
MySQL as a default for AES_Encrypt uses 128 bit, with ECB mode, which does not require an IV.
What padding mode they use is not specified, but they do say they pad it. For padding I use PaddingMode.Zeros.
In C#, use AesManaged, not RijndaelManaged since that is not recommended anymore.
If your Key is longer than 128 bits (16 bytes), then use a function below to create the correct key size, since the default MySQL AES algorithm uses 128 bit keys.
Make sure you play around with the correct Encoding and know exactly what type of character encoding you will receive back when translating the bytes to characters.
For more info go here: https://forums.mysql.com/read.php?38,193084,195959#msg-195959
Code:
public static string DecryptAESStringFromBytes(byte[] encryptedText, byte[] key)
{
// Check arguments.
if ((encryptedText == null || encryptedText.Length <= 0) || (key == null || key.Length <= 0))
{
throw new ArgumentNullException("Missing arguments");
}
string decryptedText = null;
// Create an AES object with the specified key and IV.
using (AesManaged aesFactory = new AesManaged())
{
aesFactory.KeySize = 128;
aesFactory.Key = AESCreateKey(key, aesFactory.KeySize / 8);
aesFactory.IV = new byte[16];
aesFactory.BlockSize = 128;
aesFactory.Mode = CipherMode.ECB;
aesFactory.Padding = PaddingMode.Zeros;
// Create a decryptor to perform the stream transform.
ICryptoTransform decryptor = aesFactory.CreateDecryptor();
// Create the streams used for decryption.
using (MemoryStream stream = new MemoryStream())
{
using (CryptoStream decryptStream = new CryptoStream(stream, decryptor, CryptoStreamMode.Write))
{
decryptStream.Write(encryptedText, 0, encryptedText.Length);
}
decryptedText = Encoding.Default.GetString(stream.ToArray());
}
}
return decryptedText.Trim();
}
public static byte[] AESCreateKey(byte[] key, int keyLength)
{
// Create the real key with the given key length.
byte[] realkey = new byte[keyLength];
// XOR each byte of the Key given with the real key until there's nothing left.
// This allows for keys longer than our Key Length and pads short keys to the required length.
for (int i = 0; i < key.Length; i++)
{
realkey[i % keyLength] ^= key[i];
}
return realkey;
}
Here is some working code for achieving the same encryption via C# as MySQL:
public byte[] AESEncrypt(byte[] plaintext, byte[] key) {
/*
* Block Length: 128bit
* Block Mode: ECB
* Data Padding: Padded by bytes which Asc() equal for number of padded bytes (done automagically)
* Key Padding: 0x00 padded to multiple of 16 bytes
* IV: None
*/
RijndaelManaged aes = new RijndaelManaged();
aes.BlockSize = 128;
aes.Mode = CipherMode.ECB;
aes.Key = key;
ICryptoTransform encryptor = aes.CreateEncryptor();
MemoryStream mem = new MemoryStream();
CryptoStream cryptStream = new CryptoStream(mem, encryptor,
CryptoStreamMode.Write);
cryptStream.Write(plaintext, 0, plaintext.Length);
cryptStream.FlushFinalBlock();
byte[] cypher = mem.ToArray();
cryptStream.Close();
cryptStream = null;
encryptor.Dispose();
aes = null;
return cypher;
}
For details see MySQL Bug # 16713
EDIT:
Since the above is relying on officially non-documented information (though it is working) I would recommend to avoid it and use one of the options described in the answer from Vinko Vrsalovic .
If you run SELECT AES_ENCRYPT('Test','pass')
your are sending the pass over the network unencrypted so any one can unencrypted the data.
The AES_ENCRYPT is used to store data so if the database gets hacked your data is safe, not to transmit data.
if you want data encryption over the net work connect to your mysql server using the ssl socket

Categories