meyousikmann meyousikmann - 28 days ago 7
C# Question

"Padding is invalid and cannot be removed" during decryption

First, I realize there are dozens of other posts that have answers to this question and I have read and tried them all. I still can't seem to get past this issue so am looking for a little help from somebody that knows more about crypto than I do.

Second, the code I am going to share is legacy and because I am not a crypto expert it is still not 100% clear on what everything means. It may be that some or all of this code is total rubbish and should be scrapped; however, there are a lot of other systems already using it and have stored encrypted values that have gone through this code. Changing things like the crypto algorithm is not exactly an option at this point. With that said, the private methods are the legacy code as well as the testing values (i.e. the encryption key) are all things that can't change. The two public static methods are what is new and likely causing problems, but I can't seem to figure it out.

On with the code......

class Program
{
public static string Encrypt(string key, string toEncrypt)
{
var keyArray = Convert.FromBase64String(key);
var info = Encoding.ASCII.GetBytes(toEncrypt);

var encrypted = Encrypt(keyArray, info);

return Encoding.ASCII.GetString(encrypted);
}

public static string Decrypt(string key, string cipherString)
{
var keyArray = Convert.FromBase64String(key);
var cipherText = Encoding.ASCII.GetBytes(cipherString);

var decrypted = Decrypt(keyArray, cipherText);

return Encoding.ASCII.GetString(decrypted);
}

private static byte[] Encrypt(byte[] key, byte[] info)
{
using (var cipher = Aes.Create())
{
cipher.Key = key;
cipher.Mode = CipherMode.CBC;
cipher.Padding = PaddingMode.ISO10126;

using (var ms = new MemoryStream())
{
using (var cs = new CryptoStream(ms, cipher.CreateEncryptor(), CryptoStreamMode.Write))
{
cs.Write(info, 0, info.Length);
}

var ciphertext = ms.ToArray();

var message = new byte[cipher.IV.Length + ciphertext.Length];
cipher.IV.CopyTo(message, 0);
ciphertext.CopyTo(message, cipher.IV.Length);
return message;
}
}
}

private static byte[] Decrypt(byte[] key, byte[] ciphertext)
{
using (var cipher = Aes.Create())
{
cipher.Key = key;
cipher.Mode = CipherMode.CBC;
cipher.Padding = PaddingMode.ISO10126;

var ivSize = cipher.IV.Length;
var iv = new byte[ivSize];
Array.Copy(ciphertext, iv, ivSize);
cipher.IV = iv;

var data = new byte[ciphertext.Length - ivSize];
Array.Copy(ciphertext, ivSize, data, 0, data.Length);

using (var ms = new MemoryStream())
{
using (var cs = new CryptoStream(ms, cipher.CreateDecryptor(), CryptoStreamMode.Write))
{
cs.Write(data, 0, data.Length);
}

return ms.ToArray();
}
}
}

static void Main(string[] args)
{
var newEncryptionKey = Guid.NewGuid().ToString().Replace("-", string.Empty);

var encryptedValue = Encrypt(newEncryptionKey, "test");

Console.WriteLine($"New encrypted value: {encryptedValue}");

var decryptedValue = Decrypt(newEncryptionKey, encryptedValue);

Console.WriteLine($"New decrypted value: {decryptedValue}");
}
}


So there it is. Basically, I am trying to use a test string of "test" and encrypt it using a GUID as a key. Again, I didn't choose this key and there are encrypted values already using a GUID as a key so I can't change that if at all possible. The encryption works fine, but when I go to do the decryption, I get the exception noted in the title of this question.

Any help would be GREATLY appreciated.

Answer

You can't just convert a byte[] of ciphertext to ASCII. It doesn't work like that. Character encodings are scary beasts and should not be muddled with if you don't understand them. I don't think there is a real person alive that does ;)

What you should do instead is return your result as base64, which is still a collection of ASCII characters but they are safe to be moved around as a string, and don't result in the loss of any characters.

See the modified code below:

public static string Encrypt(string key, string toEncrypt)
{
    var keyArray = Convert.FromBase64String(key);
    var info = Encoding.ASCII.GetBytes(toEncrypt);

    var encrypted = Encrypt(keyArray, info);

    return Convert.ToBase64String(encrypted);
}

public static string Decrypt(string key, string cipherString)
{
    var keyArray = Convert.FromBase64String(key);
    var cipherText = Convert.FromBase64String(cipherString);

    var decrypted = Decrypt(keyArray, cipherText);

    return Encoding.ASCII.GetString(decrypted);
}
Comments