I'm trying to read a file, encrypt it, and send it to a server over socket, where it is written. And then the other way around, read it on server, send it to client, decrypt it, and write it again.
My problem using C# Aes class is, that the input size doesn't equal the output size.
For example, when I read 4096 bytes from the file, the output size is 4112 bytes, 16 bytes more. OK, so 4112 bytes are sent and written on the server, but when I get the file again, I can only send a maximum of 4096 bytes over the socket, and then, of course, the decrypt function on client throws an exception, that the padding is invalid and cannot be removed. Sure I could try to read less bytes on the client, but that doesn't work as well.
I'm a very experienced C++ programmer, and I've done this with OpenSsl, and it worked like a charm. The input size has been always the output size, I don't know what is wrong with my functions in C#.
this is the sending part:
byte[] SendData = new byte[4096];
iBytesRead = FileRead.Read (SendData, 0, 4096);
SendData = aes.encrypt (Encoding.Default.GetString (SendData, 0, iBytesRead), iBytesRead);
String a = aes.decrypt (SendData); // no problems here because the size is correct
Socket.sendB (SendData, SendData.Length);
and the part of receiving from server:
byte[] WriteData = new byte[4096],
Temp;
if ((iBytesReceived = Socket.receiveB (ref WriteData)) == 0)
break;
if (Encoding.ASCII.GetString (WriteData, 0, iBytesReceived) == "end")
break;
for (uint i = 0; i < iBytesReceived; i++)
Temp[i] = WriteData[i];
byte[] a = Encoding.Default.GetBytes (aes.decrypt (Temp));
FileWrite.Write (a, 0, Temp.Length);
Aes functions:
public byte[] encrypt(String _InStr, int _InStrLength)
{
if (!bKeySet)
return ErrorReturn;
byte[] encrypted;
using (Aes aes = Aes.Create ())
{
aes.Key = Key;
aes.IV = IV;
//aes.Padding = PaddingMode.PKCS7;
//aes.BlockSize = 128;
//aes.KeySize = 128;
//aes.Mode = CipherMode.CFB;
ICryptoTransform encryptor = aes.CreateEncryptor(aes.Key, aes.IV);
// Create the streams used for encryption.
using (MemoryStream ms = new MemoryStream())
{
using (CryptoStream cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write))
{
using (StreamWriter sw = new StreamWriter(cs))
{
sw.Write(_InStr);
}
}
ms.Close ();
encrypted = ms.ToArray ();
}
}
return encrypted;
}
public String decrypt(byte[] _InStr)
{
if (!bKeySet)
return "";
String plaintext;
using (Aes aes = Aes.Create ())
{
aes.Key = Key;
aes.IV = IV;
//aes.Padding = PaddingMode.PKCS7;
//aes.BlockSize = 128;
//aes.KeySize = 128;
//aes.Mode = CipherMode.CBC;
ICryptoTransform decryptor = aes.CreateDecryptor(aes.Key, aes.IV);
// Create the streams used for decryption.
using (MemoryStream msDecrypt = new MemoryStream(_InStr))
{
using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
{
using (StreamReader srDecrypt = new StreamReader(csDecrypt))
{
plaintext = srDecrypt.ReadToEnd ();
}
}
}
}
return plaintext;
}
As it was said, if any padding is used, the output will be aligned to a block size. However .Net doesn't want to work with incomplete blocks when PaddingMode.None is used. You should pad data yourself before encryption(decryption) and remove added bytes after.
One of the way to do this is to wrap ICryptoTransform passed to a CryptoStream
Related
I am quite new to AES Encryption and therefore have some question about IV and Key
The code I have written works, i can both encrypt and decrypt a String
Just for fun i tried to go on a Website https://www.devglan.com/online-tools/aes-encryption-decryption
And tried to see if the website can decrypt, if i give the same key and IV. but I ran into an error
The website said "Length of secret key should be 32 for 256 bits key size"
and "Length of initialization vector must be 16 with AES."
Is there anything I have done wrong?
static void Main(string[] args)
{
byte[] key = GenerateRandomByteArray(32);
Console.WriteLine($"Key: {Convert.ToBase64String(key)}");
byte[] encrypted = EncryptMessage("test message", key);
Console.WriteLine($"Encrypted : {Convert.ToBase64String(encrypted)}");
string decrypted = DecryptMessage(encrypted, key);
Console.WriteLine($"Decrypted: {decrypted}");
Console.ReadLine();
}
private static byte[] GenerateRandomByteArray(int size)
{
using (RandomNumberGenerator rng = RandomNumberGenerator.Create())
{
byte[] buffer = new byte[size];
rng.GetBytes(buffer);
return buffer;
}
}
public static byte[] EncryptMessage(string mess, byte[] secretkey)
{
byte[] encrypted;
using (Aes aes = Aes.Create())
{
aes.Key = secretkey;
//Generates a IV with 16 random bytes
aes.IV = GenerateRandomByteArray(16);
Console.WriteLine($"IV: {Convert.ToBase64String(aes.IV)}");
// Create an encryptor to perform the stream transform.
ICryptoTransform encryptor = aes.CreateEncryptor(aes.Key, aes.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))
{
//Writes the IV, so when we decrypt we can get the first 16 bytes where IV i located
msEncrypt.Write(aes.IV, 0, aes.IV.Length);
//Write all data to the stream.
swEncrypt.Write(mess);
}
encrypted = msEncrypt.ToArray();
}
}
}
// Return the encrypted bytes from the memory stream.
return encrypted;
}
public static string DecryptMessage(byte[] mess, byte[] key)
{
string plaintext = null;
// Create an Aes object
using (Aes aes = Aes.Create())
{
//Sets the AES key
aes.Key = key;
using (MemoryStream msDecrypt = new MemoryStream(mess))
{
//Reads the first 16 bytes from the message which is where the IV i stored
byte[] iv = new byte[aes.BlockSize / 8];
msDecrypt.Read(iv, 0, iv.Length);
//Sets the IV
aes.IV = iv;
// Create a decryptor to perform the stream transform.
ICryptoTransform decryptor = aes.CreateDecryptor(aes.Key, aes.IV);
// Create the streams used for decryption.
//using (MemoryStream msDecrypt = new MemoryStream(mess))
//{
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;
}
Is i remember right GenerateRandomByteArray(32) is 256 bits for Key
And GenerateRandomByteArray(16) is 128 bits for IV
Output from Console:
Key: 3dmQoxqrAyoc5kMKQIQl8Hp4UVVCE8B64S19iNZOQRY=
IV: kO1nKUs08c/8mrlbHj3/xQ==
Encrypted : kO1nKUs08c/8mrlbHj3/xR43S5L3BJ5Ueg01xngw93I=
Decrypted: test message
I am trying to work out why a C# DLL I have is crashing since I added in AES encryption.
I initially put managed rijndael encryption in with a 256 bit key and 256 bit blocksize and the DLL worked, but I found out that the dotnet base receiving end only supports 128 bit blocksize.
However, when I changed the blocksize to 128 bits the DLL simply crashes when I encrypt. I also read the rijndael managed should not be used for new projects and so I tied other examples of AES for C#. All of THESE OTHER EXAMPLES once again crash the DLL as soon as the encrypt function is called.
I am generating both a 64 bit version of the DLL and a 32 bit version of the DLL, both crash as soon as I try to encrypt a string of around 1000 characters.
Is there some sort of initialisation I am missing, or do I need to increase memory / Stack size to use AES in the DLL? Would really value some suggestions as to why this doesn't work.
This worked for 256 bit blocksize, but crashes for 128 bit blocksize
public static byte[] AES_Encrypt(byte[] bytesToBeEncrypted, byte[] passwordBytes)
{
byte[] encryptedBytes = null;
// Set your salt here, change it to meet your flavor:
// The salt bytes must be at least 8 bytes.
byte[] saltBytes = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 };
using (MemoryStream ms = new MemoryStream())
{
using (RijndaelManaged AES = new RijndaelManaged())
{
AES.KeySize = 256;
AES.BlockSize = 128;
var key = new Rfc2898DeriveBytes(passwordBytes, saltBytes, 1000);
AES.Key = key.GetBytes(AES.KeySize / 8);
AES.IV = key.GetBytes(AES.BlockSize / 8);
AES.Mode = CipherMode.CBC;
using (var cs = new CryptoStream(ms, AES.CreateEncryptor(), CryptoStreamMode.Write))
{
cs.Write(bytesToBeEncrypted, 0, bytesToBeEncrypted.Length);
cs.Close();
}
encryptedBytes = ms.ToArray();
}
}
return encryptedBytes;
}
Various other ways I have tried so far are below:
byte[] ivBytes = ComputeSHA256(iVphrase);
byte[] plainTextBytes = Encoding.UTF8.GetBytes(plainText);
byte[] keyBytes = ComputeSHA256(password);
AesCryptoServiceProvider aes = new AesCryptoServiceProvider();
aes.BlockSize = 128;
aes.KeySize = 256;
aes.Key = keyBytes;
aes.IV = ivBytes;
aes.Padding = PaddingMode.PKCS7;
aes.Mode = CipherMode.CBC;
ICryptoTransform crypto1 = aes.CreateEncryptor(aes.Key, aes.IV);
byte[] encrypteddata = crypto1.TransformFinalBlock(plainTextBytes, 0, plainTextBytes.Length);
crypto1.Dispose();
return Convert.ToBase64String(encrypteddata);
byte[] encryptedData;
byte[] ivBytes = ComputeSHA256(iVphrase);
byte[] keyBytes = ComputeSHA256(password);
using (Aes aesAlgorithm = new AesManaged())
{
ICryptoTransform encryptor = aesAlgorithm.CreateEncryptor(keyBytes, ivBytes);
//Encryption will be done in a memory stream through a CryptoStream object
using (MemoryStream ms = new MemoryStream())
{
using (CryptoStream cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write))
{
using (StreamWriter sw = new StreamWriter(cs))
{
sw.Write(plainText);
}
encryptedData = ms.ToArray();
}
}
return Convert.ToBase64String(encryptedData);
}
byte[] ivBytes = ComputeSHA256(iVphrase);
byte[] plainTextBytes = Encoding.UTF8.GetBytes(plainText);
byte[] keyBytes = ComputeSHA256(password);
using (var symmetricKey = Aes.Create("AesManaged"))
{
symmetricKey.BlockSize = 128;
symmetricKey.Mode = CipherMode.CBC;
symmetricKey.Padding = PaddingMode.PKCS7;
symmetricKey.Key = keyBytes;
symmetricKey.IV = ivBytes;
using (var encryptor = symmetricKey.CreateEncryptor(keyBytes, ivStringBytes))
{
using (var memoryStream = new MemoryStream())
{
using (var cs = new CryptoStream(memoryStream, symmetricKey.CreateEncryptor(), CryptoStreamMode.Write))
{
cs.Write(plainTextBytes, 0, plainTextBytes.Length);
cs.Close();
}
var cipherBytes = memoryStream.ToArray();
memoryStream.Close();
return Convert.ToBase64String(cipherBytes);
}
}
}
I finally managed to get an exception output which identified the issue as being a 32 byte IV being passed in to a 128 bit Block size which generated an exception. On windows server machines the exception didn't return any result code, it simply crashed the machine. Testing on another windows 10 device correctly logged the incorrect IV length as an exception.
I was wondering why the first 16 bytes of all my strings being encrypted, then when being decrypted are missing and how to fix this if it is possible. I am encrypting like so in c#
public static string EncryptString(string b_key, string plainText)
{
byte[] iv = new byte[16];
byte[] array;
using (Aes aes = Aes.Create())
{
aes.Key = Convert.FromBase64String(b_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);
}
and decrypting in python3 like so
enc = base64.b64decode(self.text)
iv = enc[:16]
cipher = AES.new(self.key, AES.MODE_CBC, iv)
plain_text = cipher.decrypt(enc[16:])
plain_text = self.dePKCS7_padding(plain_text)
return plain_text
Is readding the first 16 bytes possible? or must be used for encryption. I also want it to crypto safe but the first 16 bytes are kind of important is this possible? anyway to get around this in either c# or python3?
Based on the discussion in comments and inputs from #MichaelFehr and #user9014097, I came up with the following code.
In this code the IV of AES will have random value created when AES.Create() is called. And the same will be used in the outcome of the encrypted value.
The decryptString method will capture the iv value from the incoming encrypted string and assign it to AES while decrypting the string.
public static string EncryptString(string b_key, string plainText)
{
byte[] array;
using (Aes aes = Aes.Create())
{
aes.Key = Convert.FromBase64String(b_key);
ICryptoTransform encryptor = aes.CreateEncryptor(aes.Key, aes.IV);
using (MemoryStream memoryStream = new MemoryStream())
{
// Adding aes.IV to the stream's start.
memoryStream.Write(aes.IV);
using (CryptoStream cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write))
{
using (StreamWriter streamWriter = new StreamWriter(cryptoStream))
{
streamWriter.Write(plainText);
}
}
array = memoryStream.ToArray();
}
}
// The final encrypted outcome will be aes.IV+encryptedtext.
return Convert.ToBase64String(array);
}
public static string DecryptString(string key, string cipherText)
{
//input is iv+encrypted text, convert them to byte array.
byte[] buffer = Convert.FromBase64String(cipherText);
// byte array for iv
byte[] iv = new byte[16];
// byte array for rest of the cipher text.
byte[] cipherBuffer = new byte[buffer.Length - 16];
// copy first 16 bytes from the cipher text to iv.
Buffer.BlockCopy(buffer, 0, iv, 0, 16);
// copy rest of the cipher text to the cipher buffer to be decrypted.
Buffer.BlockCopy(buffer, 16, cipherBuffer, 0, buffer.Length - 16);
using (Aes aes = Aes.Create())
{
aes.Key = Convert.FromBase64String(key);
aes.IV = iv;
ICryptoTransform decryptor = aes.CreateDecryptor(aes.Key, aes.IV);
using (MemoryStream memoryStream = new MemoryStream(cipherBuffer))
{
using (CryptoStream cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read))
{
using (StreamReader streamReader = new StreamReader(cryptoStream))
{
return streamReader.ReadToEnd();
}
}
}
}
}
I have following assumption in writing above code.
Length of IV is 16.
Python code (shared above) does not need split the input text based on some specific character. It takes first 16 bytes as IV value and rest of the bytes as cipher text.
I was able to encrypt and decrypt values successfully in C# using above methods.
I was not able to decrypt the value in python code as I have little to no idea on how to work with python.
You can test the outcome of above encryption in python to decrypt it. Let me know if it doesn't work as expected.
I hope this will help you solve your issue.
I'm trying to encrypt and decrypt a file using AES. The problem that I have is that when the file gets decrypted, it is broken and you can't open it. The original file has a length of 81.970 bytes and the decrypted file has a length of 81.984 bytes...so there are 14 bytes added for some reason. The problem could be in the way the file gets encrypted but I don't know what I'm doing wrong.
What am I missing here? Could it be the way I'm processing the password, the iv and the padding?
Thanks for your time!
This is the code I use to encrypt:
private AesManaged aesManaged;
private string filePathToEncrypt;
public Encrypt(AesManaged aesManaged, string filePathToEncrypt)
{
this.aesManaged = aesManaged;
this.filePathToEncrypt = filePathToEncrypt;
}
public void DoEncryption()
{
byte[] cipherTextBytes;
byte[] textBytes = File.ReadAllBytes(this.filePathToEncrypt);
using(ICryptoTransform encryptor = aesManaged.CreateEncryptor(aesManaged.Key, aesManaged.IV))
using (MemoryStream ms = new MemoryStream())
using (CryptoStream cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write))
{
cs.Write(textBytes, 0, textBytes.Length);
cs.FlushFinalBlock();
cipherTextBytes = ms.ToArray();
}
File.WriteAllBytes("EncryptedFile.aes", cipherTextBytes);
}
This is the code I use to decrypt:
private AesManaged aesManaged;
private string filePathToDecrypt;
public Decrypt(AesManaged aesManaged, string filePathToDecrypt)
{
this.aesManaged = aesManaged;
this.filePathToDecrypt = filePathToDecrypt;
}
public void DoDecrypt()
{
byte[] cypherBytes = File.ReadAllBytes(this.filePathToDecrypt);
byte[] clearBytes = new byte[cypherBytes.Length];
ICryptoTransform encryptor = aesManaged.CreateDecryptor(aesManaged.Key, aesManaged.IV);
using (MemoryStream ms = new MemoryStream(cypherBytes))
using (CryptoStream cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Read))
{
cs.Read(clearBytes, 0, clearBytes.Length);
clearBytes = ms.ToArray();
}
File.WriteAllBytes("DecryptedFile.gif", clearBytes);
}
And here is how I call the functions:
string filePathToEncrypt = "dilbert.gif";
string filePathToDecrypt = "EncryptedFile.aes";
string password = "Password";
string passwordSalt = "PasswordSalt";
Rfc2898DeriveBytes deriveBytes = new Rfc2898DeriveBytes(password, Encoding.ASCII.GetBytes(passwordSalt));
var aesManaged = new AesManaged
{
Key = deriveBytes.GetBytes(128 / 8),
IV = deriveBytes.GetBytes(16),
Padding = PaddingMode.PKCS7
};
Console.WriteLine("Encrypting File...");
var encryptor = new Encrypt(aesManaged, filePathToEncrypt);
encryptor.DoEncryption();
Thread.Sleep(300);
Console.WriteLine("Decrypting File...");
var decryptor = new Decrypt(aesManaged, filePathToDecrypt);
decryptor.DoDecrypt();
Thread.Sleep(300);
Try with:
public void DoEncryption()
{
byte[] cipherBytes;
byte[] textBytes = File.ReadAllBytes(this.filePathToEncrypt);
using (ICryptoTransform encryptor = aesManaged.CreateEncryptor(aesManaged.Key, aesManaged.IV))
using (MemoryStream input = new MemoryStream(textBytes))
using (MemoryStream output = new MemoryStream())
using (CryptoStream cs = new CryptoStream(output, encryptor, CryptoStreamMode.Write))
{
input.CopyTo(cs);
cs.FlushFinalBlock();
cipherBytes = output.ToArray();
}
File.WriteAllBytes("EncryptedFile.aes", cipherBytes);
}
and
public void DoDecrypt()
{
byte[] cypherBytes = File.ReadAllBytes(this.filePathToDecrypt);
byte[] textBytes;
using (ICryptoTransform decryptor = aesManaged.CreateDecryptor(aesManaged.Key, aesManaged.IV))
using (MemoryStream input = new MemoryStream(cypherBytes))
using (MemoryStream output = new MemoryStream())
using (CryptoStream cs = new CryptoStream(input, decryptor, CryptoStreamMode.Read))
{
cs.CopyTo(output);
textBytes = output.ToArray();
}
File.WriteAllBytes("DecryptedFile.gif", textBytes);
}
Note that the code could be modified to not use temporary byte[] and read/write directly to input/output streams.
In general you can't desume the length of the plaintext from the length of the cyphertext, so this line:
new byte[cypherBytes.Length]
was totally wrong.
And please, don't use Encoding.ASCII in 2016. It is so like previous century. Use Encoding.UTF8 to support non-english characters.
The answer may be very simple. I don't see where do u try to choose a cipher mode, so by default it probably takes CBC, as IV was inited. Then, 81.970 are padded by 14 bytes, to be divisible by 32. So when it happens, the memory you allocated was just 81.970, so the padding bytes doesn't write correctly, cause of some sort of memory leak, and when decrypt is started, unpadding doesn't work correctly.
I'm trying to get simple encryption/decryption working with AesManaged, but I keep getting an exception when trying to close the decryption stream. The string here gets encrypted and decrypted correctly, and then I get the CryptographicException "Padding was invalid and cannot be removed" after Console.WriteLine prints the correct string.
Any ideas?
MemoryStream ms = new MemoryStream();
byte[] rawPlaintext = Encoding.Unicode.GetBytes("This is annoying!");
using (Aes aes = new AesManaged())
{
aes.Padding = PaddingMode.PKCS7;
aes.Key = new byte[128/8];
aes.IV = new byte[128/8];
using (CryptoStream cs = new CryptoStream(ms, aes.CreateEncryptor(),
CryptoStreamMode.Write))
{
cs.Write(rawPlaintext, 0, rawPlaintext.Length);
cs.FlushFinalBlock();
}
ms = new MemoryStream(ms.GetBuffer());
using (CryptoStream cs = new CryptoStream(ms, aes.CreateDecryptor(),
CryptoStreamMode.Read))
{
byte[] rawData = new byte[rawPlaintext.Length];
int len = cs.Read(rawData, 0, rawPlaintext.Length);
string s = Encoding.Unicode.GetString(rawData);
Console.WriteLine(s);
}
}
The trick is to use MemoryStream.ToArray().
I also changed your code so that it uses the CryptoStream to Write, in both encrypting and decrypting. And you don't need to call CryptoStream.FlushFinalBlock() explicitly, because you have it in a using() statement, and that flush will happen on Dispose(). The following works for me.
byte[] rawPlaintext = System.Text.Encoding.Unicode.GetBytes("This is all clear now!");
using (Aes aes = new AesManaged())
{
aes.Padding = PaddingMode.PKCS7;
aes.KeySize = 128; // in bits
aes.Key = new byte[128/8]; // 16 bytes for 128 bit encryption
aes.IV = new byte[128/8]; // AES needs a 16-byte IV
// Should set Key and IV here. Good approach: derive them from
// a password via Cryptography.Rfc2898DeriveBytes
byte[] cipherText= null;
byte[] plainText= null;
using (MemoryStream ms = new MemoryStream())
{
using (CryptoStream cs = new CryptoStream(ms, aes.CreateEncryptor(), CryptoStreamMode.Write))
{
cs.Write(rawPlaintext, 0, rawPlaintext.Length);
}
cipherText= ms.ToArray();
}
using (MemoryStream ms = new MemoryStream())
{
using (CryptoStream cs = new CryptoStream(ms, aes.CreateDecryptor(), CryptoStreamMode.Write))
{
cs.Write(cipherText, 0, cipherText.Length);
}
plainText = ms.ToArray();
}
string s = System.Text.Encoding.Unicode.GetString(plainText);
Console.WriteLine(s);
}
Also, I guess you know you will want to explicitly set the Mode of the AesManaged instance, and use System.Security.Cryptography.Rfc2898DeriveBytes to derive the Key and IV from a password and salt.
see also:
- AesManaged
This exception can be caused by a mismatch of any one of a number of encryption parameters.
I used the Security.Cryptography.Debug interface to trace all parameters used in the encrypt/decrypt methods.
Finally I found out that my problem was that I set the KeySize property after setting the Key causing the class to regenerate a random key and not using the key that I was initially set up.
For whats its worth, I'll document what I faced. I was trying to read the encryptor memory stream before the CryptoStream was closed. I was naive and I wasted a day debugging it.
public static byte[] Encrypt(byte[] buffer, byte[] sessionKey, out byte[] iv)
{
byte[] encrypted;
iv = null;
using (AesCryptoServiceProvider aesAlg = new AesCryptoServiceProvider { Mode = CipherMode.CBC, Padding = PaddingMode.PKCS7 })
{
aesAlg.Key = sessionKey;
iv = aesAlg.IV;
ICryptoTransform encryptor = aesAlg.CreateEncryptor(sessionKey, iv);
// Create the streams used for encryption.
using (MemoryStream msEncrypt = new MemoryStream())
{
using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
{
csEncrypt.Write(buffer, 0, buffer.Length);
//This was not closing the cryptostream and only worked if I called FlushFinalBlock()
//encrypted = msEncrypt.ToArray();
}
encrypted = msEncrypt.ToArray();
return encrypted;
}
}
}
Moving the encryptor memory stream read after the cypto stream was closed solved the problem. As Cheeso mentioned. You don't need to call the FlushFinalBlock() if you're using the using block.
byte[] rawData = new
byte[rawPlaintext.Length];
You need to read the length of the buffer, that probably includes the necessary padding (IIRC, been a few years).
Nobody answered, that actually MemoryStream.GetBuffer returns the allocated buffer, not the real data in this buffer. In this case it returns 256-byte buffer, while it contains only 32 bytes of encrypted data.
As others have mentioned, this error can occur if the key/iv is not correctly initialized for decryption. In my case I need to copy key and iv from some larger buffer. Here's what I did wrong:
Does not work: (Padding is invalid and cannot be removed)
aes.Key = new byte[keySize];
Buffer.BlockCopy(someBuffer, keyOffset, aes.Key, 0, keySize);
aes.IV = new byte[ivSize];
Buffer.BlockCopy(someBuffer, ivOffset, aes.IV, 0, ivSize);
Works:
var key = new byte[keySize];
Buffer.BlockCopy(someBuffer, keyOffset, key, 0, keySize);
aes.Key = key;
var iv = new byte[ivSize];
Buffer.BlockCopy(someBuffer, ivOffset, iv, 0, ivSize);
aes.IV = iv;
The OP did not make this mistake, but this might be helpful for others seeing the same error.