-1

I have the following code, and it was working for almost two years. But now we have started to see random issue with the Padding. When I say random, I mean same thing works one day but doesn't work the other day. And someday it decides to work randomly.

Now, if I add the padding to none like mentioned in answers above, I could mess up all the previously encrypted files. I'm thinking to create different approach using GOTO statement in catch block in this method same way as I did when I changed the encryption key. Or is there any better approach to change padding to None?

/// <summary>
/// 
/// </summary>
[Serializable]
public static class EncryptDecrypt
{
    private static string EncryptionKey_old = "MAKV2SPBNI99212";
    private static string EncryptionKey = "Yi9BpGG1cXR01gBwGPZRTOznoJHpkGBOzisBg5jl3iRu48yhcFGdZu76fDpa5FUu";

    /// <summary>
    /// 
    /// </summary>
    /// <param name="clearText"></param>
    /// <returns></returns>
    public static string Encrypt(string clearText)
    {
        byte[] whitebs = Encoding.Unicode.GetBytes(clearText);

        using (Aes encryptor = Aes.Create())
        {

            Rfc2898DeriveBytes pdb = new Rfc2898DeriveBytes(EncryptionKey, new byte[] { 0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, 0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76 });

            encryptor.Key = pdb.GetBytes(32);

            encryptor.IV = pdb.GetBytes(16);
            encryptor.Mode = CipherMode.ECB;
            encryptor.Padding = PaddingMode.PKCS7;

            using (MemoryStream ms = new MemoryStream())
            {

                using (CryptoStream cs = new CryptoStream(ms, encryptor.CreateEncryptor(), CryptoStreamMode.Write))
                {

                    cs.Write(whitebs, 0, whitebs.Length);
                    cs.FlushFinalBlock();
                    cs.Close();
                }
                clearText = Convert.ToBase64String(ms.ToArray());
            }
        }
        return clearText.EndsWith("==") ? clearText.Remove(clearText.Length - 2) : clearText;
    }
    /// <summary>
    /// 
    /// </summary>
    /// <param name="cipherText"></param>
    /// <returns></returns>
    public static string Decrypt(string cipherText)
    {
        int attempts = 0;
        string exception = string.Empty;


        StartHere:
        cipherText = cipherText.Replace(" ", "+");

        byte[] cipherBytes;
        try { cipherBytes = Convert.FromBase64String(cipherText); }
        catch { cipherBytes = Convert.FromBase64String(cipherText + "=="); }

        using (Aes encryptor = Aes.Create())
        {

            Rfc2898DeriveBytes pdb = new Rfc2898DeriveBytes(EncryptionKey, new byte[] { 0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, 0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76 });

            encryptor.Key = pdb.GetBytes(32);

            encryptor.IV = pdb.GetBytes(16);
            encryptor.Mode = CipherMode.ECB;
            encryptor.Padding = PaddingMode.PKCS7;
            try
            {
                using (MemoryStream ms = new MemoryStream())
                {

                    using (CryptoStream cs = new CryptoStream(ms, encryptor.CreateDecryptor(), CryptoStreamMode.Write))
                    {

                        cs.Write(cipherBytes, 0, cipherBytes.Length);
                        cs.FlushFinalBlock();
                        cs.Close();
                    }

                    cipherText = Encoding.Unicode.GetString(ms.ToArray());

                }
            }
            catch
            {
                if (attempts == 2) throw;
                EncryptionKey = EncryptionKey_old;
                attempts++;
                goto StartHere;
            }
        }
        return cipherText;
    }
    '

Changing this now is not a good idea also I don't know how I would go about doing that because there are thousands of files we encrypted with this code.

messed-up
  • 493
  • 4
  • 12
  • Is that your real hard-coded encryption key that you just posted on the public internet? – Blorgbeard Nov 10 '16 at 19:35
  • No, the old one was real but not used anymore. – messed-up Nov 10 '16 at 19:41
  • I would instead try to figure out why you are getting these padding problems. If you figure that out, you don't need to worry about changing anything else. You are approaching the problem in the wrong way. – Luke Joshua Park Nov 10 '16 at 20:06
  • Just discovered a different behavior based on where it is called from. I have two places where I call for decrypting, one from Download.aspx which invokes the decrypt method on button click event and the other one is in the MVC Api designed for other projects to download the files. The Api gives file for download without any problem, but the aspx throws out exception saying "Padding is invalid...." – messed-up Nov 10 '16 at 21:13
  • Are you using a padding error as an indication that the decryption was successful? What type of condition do you expect to cause the `catch` to execute? And wow, I can't rember the last time I saw a `goto` in code. – zaph Nov 10 '16 at 22:43
  • To see what is happening to padding, **temporarily** set the decryption side to `NoPadding` on your test setup. That will accept anything, and you can look at the hex to see what you actually have there, as opposed to what you expected to find. Once you have seen what is happening with the padding, you can fix it and set the expected padding back to what it should be. – rossum Nov 11 '16 at 11:47
  • @rossum The OP is using padding to determine if the correct key was used for decryption and change keys (in the `catch` block) on bad padding, that can't work. – zaph Nov 12 '16 at 12:42

1 Answers1

2

It looks like a padding error is being used to determine is decryption is successful, that is wrong and will not work! You need another method to determine successful decryption, in this case if the correct key is used.

See PKCS#7 padding.

If decryption with the wrong key the result will be essentially random data and there is a 1/256 probability that the last byte will be 0x01 which is correct padding and there will be no padding error reported. To a lesser extent other valid padding will randomly occur.

Another method is necessary to determine if correct decryption is obtained, generally a MAC is used to authenticate the encryption. But it can be something in the data that is known, this is generally called a crib and the success rate is determined by the uniqueness of it.

Re: padding: Unless the length of the data to be encrypted is always an exact multiple of the block size (16-bytes for AES) padding is required and PKCS#7 padding is the correct padding

zaph
  • 111,848
  • 21
  • 189
  • 228