I am trying to encrypt a string of text using the RijndaelManaged class in .NET. However, I keep getting a CryptographicException ("Length of the data to decrypt is invalid"). This message isn't exactly helpful, especially since its happening when I attempt to ENCRYPT data, not decrypt. Below is the code.
public static string EncryptKMSToken(string valueToEncrypt, string encryptionKey)
{
string results = string.Empty;
using (RijndaelManaged aes = new RijndaelManaged())
{
aes.BlockSize = 128;
aes.KeySize = 128;
aes.Padding = PaddingMode.PKCS7;
aes.Mode = CipherMode.CBC;
UTF8Encoding byteTransform = new UTF8Encoding();
aes.Key = byteTransform.GetBytes(encryptionKey);
ICryptoTransform encryptor = aes.CreateDecryptor(aes.Key, aes.IV);
using (MemoryStream stream = new MemoryStream())
{
using (CryptoStream encryptStream = new CryptoStream(stream, encryptor, CryptoStreamMode.Write))
{
using (StreamWriter writer = new StreamWriter(encryptStream))
{
writer.Write(valueToEncrypt);
}
byte[] encryptedBytes = stream.ToArray();
results = byteTransform.GetString(encryptedBytes);
}
}
}
return results;
}
The error happens when the 3rd using statement closes (i.e. the line after writer.Write(valueToEncrypt). If I try to move the two lines below that inside the third using block, I end up with an empty string (and the error still happens). I pulled this code directly off of this site (http://stackoverflow.com/questions/273452/using-aes-encryption-in-c-sharp) but it doesn't seem to work. Does anyone have any ideas?
Yes, but I think you will too if you reread your code:
ICryptoTransform encryptor = aes.CreateDecryptor(aes.Key, aes.IV);
That's a decryptor named as an encryptor...
Related
I have a couple of projects in different languages that encrypt/decrypt string, for example, a php project can encrypt a string and store in a database and a c# project should be able to pull it out of the database and decrypt it.
I have a c# .net core project which I've successfully made the decryption method to decrypt string that are encrypted from other projects, but I now need a method that also does the encryption.
I have implemented a method which isn't throwing any errors but the encryption string it returns is completely wrong.
Below is my implementation of the encryption
public string encrypt(string decryptedString)
{
string encrypted;
byte[] key = Encoding.UTF8.GetBytes(CipherKey);
System.Security.Cryptography.Aes aes = System.Security.Cryptography.Aes.Create();
aes.KeySize = 256;
aes.Padding = PaddingMode.PKCS7;
aes.Key = key;
aes.IV = Encoding.UTF8.GetBytes(CipherIv);
aes.Mode = CipherMode.CBC;
ICryptoTransform decipher = aes.CreateEncryptor(aes.Key, aes.IV);
using (MemoryStream ms = new MemoryStream())
{
using (CryptoStream cs = new CryptoStream(ms, decipher, CryptoStreamMode.Write))
{
using (StreamWriter sr = new StreamWriter(cs))
{
sr.Write(decryptedString);
var encryptedString = ms.ToArray();
var result = new byte[aes.IV.Length + encryptedString.Length];
Buffer.BlockCopy(aes.IV, 0, result, 0, aes.IV.Length);
Buffer.BlockCopy(encryptedString, 0, result, aes.IV.Length, encryptedString.Length);
return Convert.ToBase64String(result);
}
}
}
}
And the equivalent method to decrypt (the decryption works fine) is below
public string decrypt(string encryptedPassword, bool throwException = false)
{
try
{
string decrypted;
byte[] key = Encoding.UTF8.GetBytes(CipherKey);
System.Security.Cryptography.Aes aes = System.Security.Cryptography.Aes.Create();
aes.KeySize = 256;
aes.Padding = PaddingMode.PKCS7;
aes.Key = key;
aes.IV = Encoding.UTF8.GetBytes(CipherIv);
aes.Mode = CipherMode.CBC;
byte[] base64decodeBytes = System.Convert.FromBase64String(encryptedPassword);
string base64Decode = Encoding.UTF8.GetString(base64decodeBytes);
ICryptoTransform decipher = aes.CreateDecryptor(aes.Key, aes.IV);
using (MemoryStream ms = new MemoryStream(base64decodeBytes))
{
using (CryptoStream cs = new CryptoStream(ms, decipher, CryptoStreamMode.Read))
{
using (StreamReader sr = new StreamReader(cs))
{
decrypted = sr.ReadToEnd();
}
}
return decrypted;
}
catch (Exception ex)
{
return encryptedPassword;
}
}
UPDATE
From the advice in the comment by 500 - Internal Server Error I have made a change which seems to have resolved the issue somewhat but I am now getting junk at the start of the string in the decryption.
For example I am doing the following to test:
string encryptionString = encryption.encrypt("Hello World");
Console.WriteLine("Encrypted String: {0}", encryptionString);
string decodedString = encryption.decrypt(encryptionString);
Console.WriteLine("Decrypted String: {0}", decodedString);
Encrypted String: Z3BmenhibnNmZ1tqa2xhZgs/GYMu49dNPNGoRROTWz4=
Decrypted String: �u�D'���);�
SKHHello World
I am trying to encrypt a string in C# using this piece of code:
public static string AesEncrypt(string plainText, byte[] Key, byte[] IV)
{
// 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);
return Encoding.UTF8.GetString(msEncrypt.ToArray());
}
This is largely based on the sample found here: example.
However, the results are somewhat strange and unpredictable - one time I ran the code and got some string as a result, the other time the resulting string (and the msEncrypt stream) were empty, and one time the application even froze. I don't understand what the problem is.
Edit:
I just ran the code again, on this line:
aesAlg.Key = Key;
something strange happened, I got this error:
Here is how I actually call this method:
public static class Authentication
{
...
private static readonly AesEncryption aes = new AesEncryption();
public static string GenerateToken()
{
AuthenticationData data = new AuthenticationData()
{
// some data
};
string serialized = JsonConvert.SerializeObject(data);
return AesEncryption.AesEncrypt(serialized, aes.Key, aes.IV);
}
}
Maybe some problem with buffers and flushing the streams.
Try to using scope just swEncript before msEncript.ToArray()
public static string AesEncrypt(string plainText, byte[] Key, byte[] IV)
{
// 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);
}
return Encoding.UTF8.GetString(msEncrypt.ToArray());
}
There are two problems with this code.
The SteamWriter isn't closed before the stream is used. There's no call to StreamWriter.Flush either. StreamWriter uses a buffer internally and writes it out to the
stream when it's full.
The StreamWriter doesn't know it's writing to
a MemoryStream, all streams look the same to it. Given how small the
plaintext is in most examples, no flushing will occur before trying
to read the data from the memory stream.
UTF8 supports only a limited set of byte sequences. Good encryption algorithms though generate essentially random sequences. Some of them won't correspond to any valid UTF8 sequence. One of the most common way to encode binary data as text is to use Base64 encoding. That's what most encryption or hashing samples show.
The code should change to something like :
public static string AesEncrypt(string plainText, byte[] Key, byte[] IV)
{
// Create an Aes object with the specified key and IV
using Aes aesAlg = Aes.Create();
aesAlg.Key = Key;
aesAlg.IV = IV;
ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV);
using MemoryStream msEncrypt = new MemoryStream();
using CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write);
using StreamWriter swEncrypt = new StreamWriter(csEncrypt);
swEncrypt.Write(plainText);
//CHANGES HERE
swEncrypt.Flush();
return Convert.ToBase64String(msEncrypt.ToArray());
}
The sample doesn't suffer from this problem because it uses explicit using blocks, so the writer is closed before the memory stream is used :
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();
}
}
Neither Visual Studio nor Resharper would suggest using a using statement in this case, as the writer is clearly closed in the innermost block.
Don't mix using styles
You can mix using blocks and statements, eg :
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();
Given the confusion caused already though, you probably shouldn't. The code isn't that much cleaner and it already caused a problem. Someone else looking at the same code in the future may get confused as well and use a bad refactoring
Maybe the key and IV pass in each time you call the AesEncrypt method were different.
For me it's working fine with the example.
static void Main(string[] args)
{
Aes aesAlg = Aes.Create();
AesEncrypt("Hello World", aesAlg.Key, aesAlg.IV);
AesEncrypt("Hello World", aesAlg.Key, aesAlg.IV);
AesEncrypt("Hello World", aesAlg.Key, aesAlg.IV);
AesEncrypt("Hello World", aesAlg.Key, aesAlg.IV);
AesEncrypt("Hello World", aesAlg.Key, aesAlg.IV);
Console.ReadKey();
}
public static string AesEncrypt(string plainText, byte[] Key, byte[] IV)
{
// 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))
{
swEncrypt.Write(plainText);
}
Console.WriteLine(BitConverter.ToString(msEncrypt.ToArray()));
return Encoding.UTF8.GetString(msEncrypt.ToArray());
}
}
}
}
I am trying to decrypt a string in C# using AES:
public static string AesDecrypt(byte[] cipherText, byte[] Key, byte[] IV)
{
string plaintext = null;
// Create an Aes object with the specified key and IV
using Aes aesAlg = Aes.Create();
aesAlg.Padding = PaddingMode.Zeros;
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;
}
The encoded data is JSON, but when I decrypt it, I get all the right data except that the closing } of the JSON content is missing.
I think that the AES itself is not my problem here. I have doubts in the
plaintext = srDecrypt.ReadToEnd();
since only the last character is missing.
I don't know if I am supposed to flush any of the streams explicitly, but in any case it's a very curious problem.
Here's the full code for the encryption:
public static string AesEncrypt(string plainText, byte[] Key, byte[] IV)
{
// Create an Aes object with the specified key and IV
using Aes aesAlg = Aes.Create();
aesAlg.Padding = PaddingMode.Zeros;
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);
swEncrypt.Flush();
return Convert.ToBase64String(msEncrypt.ToArray());
}
And this is how I call the decryption method:
public static AuthenticationData ParseAuthenticationToken(string token)
{
byte[] tokenBytes = Convert.FromBase64String(token);
string json = AesEncryption.AesDecrypt(tokenBytes, aes.Key, aes.IV);
return JsonConvert.DeserializeObject<AuthenticationData>(json);
}
The problem is in your encryption code. Although you're calling seEncrypt.Flush(), you're not calling csEncrypt.FlushFinalBlock(). That automatically happens when the stream is disposed, but you're not doing that until after you've called msEncrypt.ToArray(). I would rewrite that code as:
MemoryStream msEncrypt = new MemoryStream();
using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
{
using StreamWriter swEncrypt = new StreamWriter(csEncrypt);
swEncrypt.Write(plainText);
// swEncrypt is disposed here, flushing it. Then csEncrypt is disposed,
// flushing the final block.
}
return msEncrypt.ToArray();
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
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.