"Padding Is Invalid and Cannot Be Removed" Using Aesmanaged

Padding is invalid and cannot be removed using AesManaged

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

AES Padding is Invalid And Cannot Be Removed

Probably because you are reusing the same ICryptoTransform objects (_sifreleyici and _desifreleyici). At some point, the transform object can't be reused anymore and therefore the interface has a property to determine that. The ICryptoTransform.CanReuseTransform property.

Consequently, you need to check this property and recreate the objects when you get false.

Example

private readonly byte[] Key, IV;

public void KriptoAlgoritmasiniAyarla(
string password,
string salt,
SymmetricAlgorithm algorithm)
{
// ...

Key = // Get the key..
IV = // Get the IV..
}

private ICryptoTransform encryptor;
private ICryptoTransform Encryptor
{
get
{
if (encryptor == null || !encryptor.CanReuseTransform)
{
encryptor?.Dispose();
encryptor = Algorithm.CreateEncryptor(Key, IV);
}
return encryptor;
}
}

private ICryptoTransform decryptor;
private ICryptoTransform Decryptor
{
get
{
if (decryptor == null || !decryptor.CanReuseTransform)
{
decryptor?.Dispose();
decryptor = Algorithm.CreateDecryptor(Key, IV);
}
return decryptor;
}
}

Then use these two properties in the related methods to create the CryptoStream.


Alternative

I'd like to propose the code below as an alternative that can be used with the classes that derive from the SymmetricAlgorithm abstract class.

public class SymmetricCrypto<T> : IDisposable where T : SymmetricAlgorithm, new()
{
private readonly T Algorithm = new T();

public SymmetricCrypto()
{
Algorithm.GenerateKey();
Algorithm.GenerateIV();
}

public SymmetricCrypto(byte[] key, byte[] iv)
{
Algorithm.Key = key;
Algorithm.IV = iv;
}

public SymmetricCrypto(string pass)
{
var bytes = Encoding.UTF8.GetBytes(pass);
var rfc = new Rfc2898DeriveBytes(pass,
new SHA256Managed().ComputeHash(bytes), 1000);

Algorithm.Key = rfc.GetBytes(Algorithm.LegalKeySizes[0].MaxSize / 8);
Algorithm.IV = rfc.GetBytes(Algorithm.LegalBlockSizes[0].MinSize / 8);
}

public SymmetricCrypto(byte[] pass)
{
var rfc = new Rfc2898DeriveBytes(pass,
new SHA256Managed().ComputeHash(pass), 1000);

Algorithm.Key = rfc.GetBytes(Algorithm.LegalKeySizes[0].MaxSize / 8);
Algorithm.IV = rfc.GetBytes(Algorithm.LegalBlockSizes[0].MinSize / 8);
}

public byte[] Encrypt(string input) =>
Transform(Encoding.UTF8.GetBytes(input), Algorithm.CreateEncryptor());

public string Decrypt(byte[] input) =>
Encoding.UTF8.GetString(Transform(input, Algorithm.CreateDecryptor()));

private byte[] Transform(byte[] input, ICryptoTransform cryptoTrans)
{
using (var ms = new MemoryStream())
using (var cs = new CryptoStream(ms, cryptoTrans, CryptoStreamMode.Write))
{
cs.Write(input, 0, input.Length);
cs.FlushFinalBlock();

return ms.ToArray();
}
}

public void Dispose() => Algorithm.Dispose();
}

Usage:

void SomeCaller()
{
using (var crypt = new SymmetricCrypto<AesManaged>("password"))
{
var bytes = crypt.Encrypt("Plain Text....");
// ...

var plainText = crypt.Decrypt(bytes);
// ...
}
}

Padding is invalid and cannot be removed?

Rijndael/AES is a block cypher. It encrypts data in 128 bit (16 character) blocks. Cryptographic padding is used to make sure that the last block of the message is always the correct size.

Your decryption method is expecting whatever its default padding is, and is not finding it. As @NetSquirrel says, you need to explicitly set the padding for both encryption and decryption. Unless you have a reason to do otherwise, use PKCS#7 padding.

C#: AES error: Padding is invalid and cannot be removed. Same key and everything, help

Based on your edit:

EDIT: It seems that the size of the encrypted data is 48 bytes (12 bytes more than the original). Why is that so? I thought that it only adds bytes if they are not a multiple of the block size (16 bytes, my data is 32 bytes). Is data always larger, and with constant increase (I need to know that in order to properly read and decrypt).

If the encrypted data is 48 bytes, thats 16 bytes larger than your original array. This makes sense because the algorithm with pad the data because the default is PKCS7 (even if the size matches the block size, because it pads to the next multiple of the block-size). If you wish to keep it exactly 32 bytes, just change the Padding to None

aes.Padding = PaddingMode.None;

AesManaged - Padding is Invalid and Cannot Be Removed - Reading from .Txt File

I'm sorry I deleted my comment (it was wrong in that context), but I reworked your example to have a little less boilerplate and be able to encrypt and decrypt properly. The problem is that you're generating a new and different Key/IV pair to decrypt from the one you used to encrypt. Of course it won't be able to decrypt. So, here is the part to make it work:

        byte[] key;
byte[] iv;

string json = JsonConvert.SerializeObject(credentials);
using (AesManaged myAes = new AesManaged())
{
key = myAes.Key;
iv = myAes.IV;
byte[] encrypted = ControlHelperscs.EncryptStringToBytes_Aes(json, key, iv);
File.WriteAllBytes(subPath, encrypted);
}

byte[] file = File.ReadAllBytes(subPath);

string decrypt = ControlHelperscs.DecryptStringFromBytes_Aes(file, key, iv);
credentials = JsonConvert.DeserializeObject<LoginModel>(decrypt);

and here are the slightly reworked heavy-lifting methods to be a bit more compact:

    public static byte[] EncryptStringToBytes_Aes(string plainText, byte[] key, byte[] iv)
{
// Check arguments.
if (plainText is null)
{
throw new ArgumentNullException(nameof(plainText));
}

if (plainText.Length == 0)
{
throw new ArgumentOutOfRangeException(nameof(plainText), plainText, "length cannot be zero");
}

if (key is null)
{
throw new ArgumentNullException(nameof(key));
}

if (key.Length == 0)
{
throw new ArgumentOutOfRangeException(nameof(key), key, "length cannot be zero");
}

if (iv is null)
{
throw new ArgumentNullException(nameof(iv));
}

if (iv.Length == 0)
{
throw new ArgumentOutOfRangeException(nameof(iv), iv, "length cannot be zero");
}

// Create an AesManaged object
// with the specified key and IV.
// Create an encryptor to perform the stream transform.
// Create the streams used for encryption.
using (SymmetricAlgorithm aesAlg = new AesManaged { Key = key, IV = iv })
using (ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV))
using (MemoryStream msEncrypt = new MemoryStream())
using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
using (TextWriter swEncrypt = new StreamWriter(csEncrypt))
{
// Write all data to the stream.
swEncrypt.Write(plainText);
swEncrypt.Flush();
csEncrypt.FlushFinalBlock();

// Return the encrypted bytes from the memory stream.
return msEncrypt.ToArray();
}
}

public static string DecryptStringFromBytes_Aes(byte[] cipherText, byte[] key, byte[] iv)
{
// Check arguments.
if (cipherText is null)
{
throw new ArgumentNullException(nameof(cipherText));
}

if (cipherText.Length == 0)
{
throw new ArgumentOutOfRangeException(nameof(cipherText), cipherText, "length cannot be zero");
}

if (key is null)
{
throw new ArgumentNullException(nameof(key));
}

if (key.Length == 0)
{
throw new ArgumentOutOfRangeException(nameof(key), key, "length cannot be zero");
}

if (iv is null)
{
throw new ArgumentNullException(nameof(iv));
}

if (iv.Length == 0)
{
throw new ArgumentOutOfRangeException(nameof(iv), iv, "length cannot be zero");
}

// Create an AesManaged object
// with the specified key and IV.
// Create a decryptor to perform the stream transform.
// Create the streams used for decryption.
using (SymmetricAlgorithm aesAlg = new AesManaged { Key = key, IV = iv })
using (ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV))
using (Stream msDecrypt = new MemoryStream(cipherText))
using (Stream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
using (TextReader srDecrypt = new StreamReader(csDecrypt))
{
// Read the decrypted bytes from the decrypting stream
// and place them in a string.
return srDecrypt.ReadToEnd();
}
}


Related Topics



Leave a reply



Submit