Padding Is Invalid and Cannot Be Removed

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.

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);
// ...
}
}

How to fix Padding is invalid and cannot be removed when encrypting and decrypting in the same process

The variable password, and the parameter with the same name, point to the same constant string. The first of your methods will zero that string out.

    static void Main(string[] args)
{
string password = "Password123!";

encFile(@"C:\KaliPatriot\test.xml", password);
// password is now "\0\0\0\0\0\0\0\0\0"
decFile(@"C:\KaliPatriot\test.dat", password);
Console.WriteLine(output);
}

Using a string like this is very dangerous. Strings are supposed (and assumed) to be immutable and .NET also uses interning for strings.

You have managed to get UB (Undefined Behaviour) in C#, not something to be proud of.

Why RijndaelManaged raises the following exception: Padding is invalid and cannot be removed?

You are decrypting the data incorrectly. Try this:

public static byte[] Decrypt(byte[] encryptedData, byte[] key, byte[] iv)
{
byte[] data;
using (var aes = new RijndaelManaged()
{
Padding = PaddingMode.PKCS7,
Mode = CipherMode.CBC,
KeySize = KEY_SIZE,
BlockSize = BLOCK_SIZE
})
{
var decryptor = aes.CreateDecryptor(key, iv);

using (var encStream = new MemoryStream(encryptedData))
{
using (var csDecrypt = new CryptoStream(encStream, decryptor, CryptoStreamMode.Read))
{
using (var msData = new MemoryStream())
{
csDecrypt.CopyTo(msData);
data = msData.ToArray();
}
}
}
}
return data;
}

Padding is invalid and cannot be removed - decryption in c# (encryption done in java)

I used my own decryption method for c# aes and hashKey as well as I know they are working :-).

Giving these data as input for the Java encryption:

String string_key = "mySecretKey";
String stringToEncrypt = "The quick brown fox jumps over the lazy dog";

I'm getting the

encryptedLicense: lrgzfdMTetZKeAFlCAbCDBL4VhtpVGdhTESl9QNgs5b0KOWke1CnKQQf+xmB+/mK

Using this string and the given string_key to C# is puts out:

plaintext expect : The quick brown fox jumps over the lazy dog
plaintext from C#: The quick brown fox jumps over the lazy dog

Security warning: this code uses a fixed encryption key and a fixed initialization vector that makes the
complete encryption UNSECURE. The code has not proper exception handling and is for educational purpose only.

C#-code:

using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;

public class Program {
public static void Main() {
Console.WriteLine("Padding is invalid and cannot be removed - decryption in c# (encryption done in java)");

string plaintextExpected = "The quick brown fox jumps over the lazy dog";
string encryptedLicense = "lrgzfdMTetZKeAFlCAbCDBL4VhtpVGdhTESl9QNgs5b0KOWke1CnKQQf+xmB+/mK";
string string_key = "mySecretKey";
string plaintext = "";

// decryption
plaintext = decryptFromBase64(hashKey(string_key), encryptedLicense);
Console.WriteLine("plaintext expect : " + plaintextExpected);
Console.WriteLine("plaintext from C#: " + plaintext);
}

public static byte[] hashKey(string value)
{
byte[] bytes = System.Text.Encoding.UTF8.GetBytes(value);
SHA1 sha = new SHA1CryptoServiceProvider();
byte[] sha1Hash = sha.ComputeHash(bytes);
byte[] sha1HashLength = new byte[16];
Array.Copy(sha1Hash, 0, sha1HashLength, 0, 16);
return sha1HashLength;
}

static string decryptFromBase64(byte[] key, string data) {
string decryptedtext;
using(Aes aesAlg = Aes.Create()) {
aesAlg.Key = key;
string initVector = "RgUkXp2s5v8y/B?E";
byte[] IV = Encoding.UTF8.GetBytes(initVector);
byte[] cipherText = Convert.FromBase64String(data);
aesAlg.IV = IV;
aesAlg.Mode = CipherMode.CBC;
ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV);
using(var msDecrypt = new MemoryStream(cipherText)) {
using(var csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read)) {
using(var srDecrypt = new StreamReader(csDecrypt)) {
decryptedtext = srDecrypt.ReadToEnd();
}
}
}
}
return decryptedtext;
}
}

Edit 1:
In my Java code I changed the following line:

//String string_key = "mySecretKey";
String string_key = "BFEBFBFF000306D4";

and got as result:

encryptedLicense: 7QWzpg/rVE6AhmcGphFT9uswU8hgKjG3i9NHJHCn/fKITYNIljOb28+cbh5y5JEA

Changing my C#-code as follow:

//string encryptedLicense = "lrgzfdMTetZKeAFlCAbCDBL4VhtpVGdhTESl9QNgs5b0KOWke1CnKQQf+xmB+/mK";
string encryptedLicense = "7QWzpg/rVE6AhmcGphFT9uswU8hgKjG3i9NHJHCn/fKITYNIljOb28+cbh5y5JEA";
//string string_key = "mySecretKey";
string string_key = "BFEBFBFF000306D4";

gets the result:

plaintext expect : The quick brown fox jumps over the lazy dog
plaintext from C#: The quick brown fox jumps over the lazy dog

So everything is working.

Padding is invalid and cannot be removed exception

Doing cs.Read(x, 0, x.Length) is not the correct thing to do. You need to put the byte array in the memory stream's constructor then read out the data to a string using cs.Read( in a loop till you have all the bytes read.

public static string Decrypt(byte[] x)
{
StringBuilder plainString = new StringBuilder();
byte[] plainBytes = new byte[2048];
byte[] plainKey;
using(var desObj = Rijndael.Create()) //this should be a local variable and be disposed of.
{
plainKey = Encoding.ASCII.GetBytes("0123456789abcdef");//Change the key.
desObj.Key = plainKey;
desObj.Mode = CipherMode.CFB;
desObj.Padding = PaddingMode.PKCS7;
using(MemoryStream ms = new MemoryStream(x)) //pass the byte[] in to the memory stream.
using(CryptoStream cs = new CryptoStream(ms, desObj.CreateDecryptor(), CryptoStreamMode.Read)) //this should be disposed of instead of calling .Close manually.
{
int bytesRead;
while((bytesRead = cs.Read(plainBytes, 0, plainBytes.Lenght)) > 0)
{
var str = Encoding.ASCII.GetString(plainBytes, 0, bytesRead);
plainString.Append(str);
}
}
}
return str.ToString();
}

or by wrapping it in a StreamReader to make the code easier.

public static string Decrypt(byte[] x)
{
byte[] plainKey;
using(var desObj = Rijndael.Create()) //this should be a local variable and be disposed of.
{
plainKey = Encoding.ASCII.GetBytes("0123456789abcdef");//Change the key.
desObj.Key = plainKey;
desObj.Mode = CipherMode.CFB;
desObj.Padding = PaddingMode.PKCS7;
using(MemoryStream ms = new MemoryStream(x)) //pass the byte[] in to the memory stream.
using(CryptoStream cs = new CryptoStream(ms, desObj.CreateDecryptor(), CryptoStreamMode.Read)) //this should be disposed of instead of calling .Close manually.
using(StreamReader sr = new StreamReader(cs, Encoding.ASCII))
{
return sr.ReadToEnd();
}
}
}

(Note: I would reccomend changing your encrypting code to be a StreamWriter for similar reasons. Also ASCII is a bad encoding choice, it only supports 7 bit charactors. Use Enocding.UTF8 instead, it is a much more common encoding and will still take up the same amount of space if you don't use any special characters but you don't loose the characters if you do end up having them in your string like you will with ASCII encoding)


UPDATE: there is a 2nd problem with your code. You never set desObj.IV on the sending or receiving side. It will use a randomly generated IV if you do not explicitly assign one. Fixing the MemoryStream error and the IV error will make the code work.

Here is a full example you can even see run online

using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;

public class Program
{
public static void Main()
{

var key = Encoding.ASCII.GetBytes("0123456789abcdef");//Change the key.

var data = Encrypt("Hello World",key);
var str = Decrypt(data, key);
Console.WriteLine(str);
}

public static byte[] Encrypt(string plaintext, byte[] key)
{

using(var desObj = Rijndael.Create())
{
desObj.Key = key;
desObj.Mode = CipherMode.CFB;
desObj.Padding = PaddingMode.PKCS7;
using(var ms = new MemoryStream())
{
//Append the random IV that was generated to the front of the stream.
ms.Write(desObj.IV, 0, desObj.IV.Length);

//Write the bytes to be encrypted.
using(CryptoStream cs = new CryptoStream(ms, desObj.CreateEncryptor(), CryptoStreamMode.Write))
{
var plainTextBytes = Encoding.UTF8.GetBytes(plaintext);
cs.Write(plainTextBytes, 0, plainTextBytes.Length);
}
return ms.ToArray();
}
}
}

public static string Decrypt(byte[] cyphertext, byte[] key)
{

using(MemoryStream ms = new MemoryStream(cyphertext))
using(var desObj = Rijndael.Create())
{
desObj.Key = key;
desObj.Mode = CipherMode.CFB;
desObj.Padding = PaddingMode.PKCS7;

//Read the IV from the front of the stream and assign it to our object.
var iv = new byte[16];
var offset = 0;
while(offset < iv.Length)
{
offset += ms.Read(iv, offset, iv.Length - offset);
}
desObj.IV = iv;

//Read the bytes to be decrypted
using(var cs = new CryptoStream(ms, desObj.CreateDecryptor(), CryptoStreamMode.Read))
using(var sr = new StreamReader(cs, Encoding.UTF8))
{
return sr.ReadToEnd();
}
}
}
}


Related Topics



Leave a reply



Submit