0

I've got weird problem because only SOMETIMES I'm getting exepction

Padding is invalid and cannot be removed.

Why am I getting it? It is Windows Phone 8.0 project. I have searched and found that I should add this

aesManaged.Padding = PaddingMode.None

but it's WP8 and it doesnt have got PaddingMode.

 public LoginView()
        {
            this.InitializeComponent();
            try
            {

                string original = "Here is some data to encrypt!";

                AesManaged myAes = new AesManaged();
                byte[] encrypted = EncryptStringToBytes_Aes(original, myAes.Key, myAes.IV);
                Console.WriteLine("Original:   {0}", original);

                var str = System.Text.Encoding.Unicode.GetString(encrypted,0,encrypted.Length);
                var str1 = System.Text.Encoding.Unicode.GetBytes(str);


                AesManaged myAes1 = new AesManaged();

                myAes1.Key = myAes.Key;
                myAes1.IV = myAes.IV;
                myAes.Clear();
                string roundtrip = DecryptStringFromBytes_Aes(str1, myAes1.Key, myAes1.IV); // HERE IS EXCEPTION
                Console.WriteLine("Round Trip: {0}", roundtrip);

            }
            catch (Exception e)
            {
                Console.WriteLine("Error: {0}", e.Message);
            }
        }

static byte[] EncryptStringToBytes_Aes(string plainText, byte[] Key, byte[] IV)
    {
        // Check arguments.
        if (plainText == null || plainText.Length <= 0)
            throw new ArgumentNullException("plainText");
        if (Key == null || Key.Length <= 0)
            throw new ArgumentNullException("Key");
        if (IV == null || IV.Length <= 0)
            throw new ArgumentNullException("Key");
        byte[] encrypted;
        // Create an AesManaged object
        // with the specified key and IV.
        using (AesManaged aesAlg = new AesManaged())
        {
            aesAlg.Key = Key;
            aesAlg.IV = IV;

            // Create a decrytor 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);
                    }
                    encrypted = msEncrypt.ToArray();
                }
            }
        }


        // Return the encrypted bytes from the memory stream.
        return encrypted;

    }



    static string DecryptStringFromBytes_Aes(byte[] cipherText, byte[] Key, byte[] IV)
    {
        // Check arguments.
        if (cipherText == null || cipherText.Length <= 0)
            throw new ArgumentNullException("cipherText");
        if (Key == null || Key.Length <= 0)
            throw new ArgumentNullException("Key");
        if (IV == null || IV.Length <= 0)
            throw new ArgumentNullException("Key");

        // Declare the string used to hold
        // the decrypted text.
        string plaintext = null;

        // Create an AesManaged object
        // with the specified key and IV.
        using (AesManaged aesAlg = new AesManaged())
        {
            aesAlg.Key = Key;
            aesAlg.IV = IV;

            // Create a decrytor 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;

    }
Icet
  • 678
  • 2
  • 13
  • 31
  • 2
    Why you're getting it: Most encryption algorithms work in blocks of X bytes. If the data you are encrypting doesn't completely fill the last block it needs to be padded with a specific character (depending on the padding setting). The reason you're only getting it sometimes is probably because sometimes the data lines up with the block size and other times it doesn't. – Mark Dec 08 '15 at 13:30
  • Why are you creating 'myAes1'? That's completely useless and not needed at all. Calling the Clear() method on 'myAes' is also useless since you are not using it anymore. – Camilo Terevinto Dec 08 '15 at 13:30
  • @Mark Icet clearly said that in WP8 you can't change the Padding mode, it's static. – Camilo Terevinto Dec 08 '15 at 13:32
  • @cFrozenDeath myAes1 is just for testing and it must be here – Icet Dec 08 '15 at 13:32
  • @Mark so how to solve it? What do I need to add to the code? – Icet Dec 08 '15 at 13:33
  • @Icet I'd suggest you remove the StreamWriter and StreamReader and instead write/read the UTF8 bytes of the text. – Camilo Terevinto Dec 08 '15 at 13:34
  • 3
    You are decoding the encrypted byte array and then back to an array. If you really need to have a binary string representation convert the string to Base64 (with the methods found on `System.Convert`) and from a string back to a byte array. – rene Dec 08 '15 at 13:36
  • According to https://msdn.microsoft.com/en-us/library/system.security.cryptography.aesmanaged(v=vs.95).aspx "the padding mode is always PKCS7.". So that should be fine. The problem is probably in your bytes -> string -> bytes conversion. What happens if you call it directly on the "encrypted" variable? – Mark Dec 08 '15 at 13:37
  • @Mark If i change str1 to encrypted it works perfectly but I need str1 there – Icet Dec 08 '15 at 13:40
  • 2
    @Icet it's probably the conversion to string and back to bytes that's the problem then as cFrozenDeath and rene have also mentioned. – Mark Dec 08 '15 at 13:42

1 Answers1

3

Change this:

var str = System.Text.Encoding.Unicode.GetString(encrypted,0,encrypted.Length);
var str1 = System.Text.Encoding.Unicode.GetBytes(str);

for this:

var str = Convert.ToBase64String(encrypted);
var str1 = Convert.FromBase64String(str);

The Encoding classes should not be used for converting string to bytes nor vice-versa.

You should also remove the StreamReader and StreamWriter and write/read directly to/from the MemoryStream

Camilo Terevinto
  • 31,141
  • 6
  • 88
  • 120
  • Thanks! It works ! Can you explain why we should not use Encoding class to converting like this? – Icet Dec 08 '15 at 13:42
  • 1
    @Icet sure, read here: http://stackoverflow.com/questions/3866316/whats-the-difference-between-utf8-utf16-and-base64-in-terms-of-encoding – Camilo Terevinto Dec 08 '15 at 14:02