简体   繁体   中英

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

I'm quite new to C# so please be patient with me. I know this question was asked a lot if times, but I couldn't find an answer to my problem.

I'm saving some data and before writing it to a file I convert it to binary and store it in array, which I encrypt and then write to file. I encrypt data in chunks (32 bytes). In the same way I read data in chunks of 32 bytes and then decrypt that data and then this should repeat till the end of file. But when it comes to decryption the following error is thrown:

Padding is invalid and cannot be removed.

I use the same key and iv (hardcoded just until I get it working)

Here is my encryption code, which works without problems:

        //result
        byte[] data = new byte[32];

        //setup encryption (AES)
        SymmetricAlgorithm aes = Aes.Create();
        byte[] key = { 145, 12, 32, 245, 98, 132, 98, 214, 6, 77, 131, 44, 221, 3, 9,50};
        byte[] iv = { 15, 122, 132, 5, 93, 198, 44, 31, 9, 39, 241, 49, 250, 188, 80, 7 };
        ICryptoTransform encryptor = aes.CreateEncryptor(key, iv);

        FileStream fStream = new FileStream(file, FileMode.OpenOrCreate, FileAccess.Write, FileShare.Read, 1024, false);

        //prepare data to write (byte array 'data') ...

        //encrypt
               MemoryStream m = new MemoryStream();
               using (Stream c = new CryptoStream(m, encryptor, CryptoStreamMode.Write))
                   c.Write(data, 0, data.Length);
               data = m.ToArray();
               fStream.Write(data, 0, data.Length);

And here is my decryption code:

FileStream fStream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read, 4096, false);

            //setup encryption (AES)
            SymmetricAlgorithm aes = Aes.Create();
            byte[] key = { 145, 12, 32, 245, 98, 132, 98, 214, 6, 77, 131, 44, 221, 3, 9, 50 };
            byte[] iv = { 15, 122, 132, 5, 93, 198, 44, 31, 9, 39, 241, 49, 250, 188, 80, 7 };
            ICryptoTransform decryptor = aes.CreateDecryptor(key, iv);

            //result
            byte[] data = new byte[32];

            //loop for reading the whole file ...
            int len = fStream.Read(data, 0, 32);

            //decrypt
                MemoryStream m = new MemoryStream();
                using (Stream c = new CryptoStream(m, decryptor, CryptoStreamMode.Write))
                    c.Write(data, 0, data.Length); //The exception is thrown in this line                  
                data = m.ToArray();

                //using the decrypted data and then looping back to reading and decrypting...

I tried all I could think of (which is not much because I'm very new to cryptography), I searched everywhere and I couldn't find a solution to my problem. I also helped myself with the book C# in a Nutshell .

If anyone has ideas on why this could happen I'll be really thankful because I have no ideas.

Thank you for your time and answers.

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).

Note: I can't directly use other streams because I need to have control over the output format and I believe it is also safer and faster to encrypt in memory.

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;

You seem to be treating the length of the plaintext as the length of the ciphertext. That's not a safe assumption.

Why are you copying between FileStream and MemoryStream , you can pass a FileStream directly to the encryptor/decryptor.

In PKCS7, there is a minimum of one padding byte (to store the number of padding bytes). So the output size will be Ceil16(input.Length + 1) , or (input.Length & ~15) + 1 .

The short of it is that AES encrypts messages in blocks of 16 bytes. If your message isn't an even multiple of 16 bytes, the algorithm needs to be a little different for the last block; specifically, the last block must be "padded" with a value known to the algorithm as a padding value (usually zero, sometimes something else like a space character value).

You're doing that yourself, by putting the data into a fixed-length byte array. You padded the data yourself, but the decrypter is now attempting to de-pad the last block and getting byte values it doesn't recognize as the padding that its encrypter counterpart would have added.

The key is not to pad the message. You can use the BitConverter class to cast byte arrays to and from IConvertible types (value types and strings), and then use that instead of rolling your own byte array. Then, when you decrypt, you can read from the decryption stream up to the ciphertext length, but don't expect there to be that many actual bytes in the decrypted result.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM