-1

I get error "the input data is not a complete block", I dont know if my code is wrong or something is missing. i try to encrypt/decrypt bytes with same lenght.

=byte[] plain => MyEnc(plain) => byte[] encrypted => MyDec(encrypt) => byte[] plain

Plain and encrypted have the same length.

This is my encryption code:

public static byte[] MyEnc(byte[] Input)
    {
        byte[] inputencdec = Input;
        byte[] encrypted;
        using (MemoryStream mstream = new MemoryStream())
        {
            using (AesCryptoServiceProvider encdec = new AesCryptoServiceProvider())
            {
                encdec.BlockSize = 128;
                encdec.KeySize = 256;
                encdec.Key = ASCIIEncoding.ASCII.GetBytes(Key);
                encdec.IV = ASCIIEncoding.ASCII.GetBytes(IV);
                ICryptoTransform icrypt = encdec.CreateEncryptor(encdec.Key, encdec.IV);

                using (CryptoStream cryptoStream = new CryptoStream(mstream,
                    icrypt, CryptoStreamMode.Write))
                {
                    cryptoStream.Write(inputencdec, 0, inputencdec.Length);
                }

            }
            encrypted = mstream.ToArray();
        }

        return encrypted;
    }

this is my decryption code:

public static byte[] MyDec(byte[] Input)
    {
        byte[] inputencdec = Input;
        byte[] buffer = new byte[Input.Length];
        int totalRead = 0;
        byte[] plain;

        MemoryStream plainStream = new MemoryStream();

        using (MemoryStream mStream = new MemoryStream(inputencdec))
        {
            using (AesCryptoServiceProvider encdec = new AesCryptoServiceProvider())
            {
                encdec.BlockSize = 128;
                encdec.KeySize = 256;
                encdec.Key = ASCIIEncoding.ASCII.GetBytes(Key);
                encdec.IV = ASCIIEncoding.ASCII.GetBytes(IV);
                ICryptoTransform icrypt = encdec.CreateDecryptor(encdec.Key, encdec.IV);

                using (CryptoStream cryptoStream = new CryptoStream(mStream, icrypt, CryptoStreamMode.Read))
                {
                    while (true)
                    {
                        int read = cryptoStream.Read(buffer, 0, inputencdec.Length);

                        if (read == 0)
                            break;
                        else
                            plainStream.Write(buffer, totalRead, read);

                        totalRead += read;
                    }

                }
            }

            plain = plainStream.ToArray();
        }

        return plain;
    }
Edward
  • 9
  • 5
  • It is better (and even policy) to use C# as tag instead of in the title. It will enhance the exposure of your question and it will auto-highlight your code. Pleas always provide full stack traces of the error and a hint in the code where the exception is occurring, as we don't have the line numbers. – Maarten Bodewes May 13 '18 at 13:27
  • Error code at `int read = cryptoStream.Read(buffer, 0, inputencdec.Length);` If plain and cipher have different length. so i cant make both have the same length? or use another cipher mode?. What i want to try, example if i have 50k Bytes and i parse bytes from 20k-40k. and just encypt/decrypt that parse bytes and add to that file again. – Edward May 13 '18 at 20:03
  • You can use a streaming mode of operation such as counter mode. This is the most common streaming mode but it is not available for .NET for some braindead reason (a lot of the Mickeysoft crypto API is braindead in that way, I guess they are missing the contact with developers, developers, developers... However there is CFB mode which is an old mode that doesn't require padding either. But I can see now that the buffer is the same size as the ciphertext; that means your ciphertext is of the wrong size; which means the generation of the ciphertext was likely screwed up. – Maarten Bodewes May 13 '18 at 21:22
  • So CFB mode will make plain and cipher have same bytes lenght ? – Edward May 13 '18 at 22:59
  • Yeah, **if** you can derive the IV or change the key for every message. The IV could for instance double as message number to avoid replay attacks. Note that neither CBC nor CFB provides authenticity / integrity; you'd need e.g. GCM for that, but it adds an authentication tag to the ciphertext. – Maarten Bodewes May 13 '18 at 23:29
  • Ok ty that error has been solved. But i have last question. Can i make that AES encrypting do on parallelism processing? – Edward May 15 '18 at 23:42
  • Altered answer, please show it some love by accepting it. – Maarten Bodewes May 16 '18 at 10:50

1 Answers1

0

Plain and encrypted are not the same length for CBC mode encryption, which you are using. The plaintext needs to be padded before it can be encrypted, so the ciphertext size is always larger than the plaintext message for CBC (which is the default mode that the decryptor is using).

Streaming modes do not need to expand the ciphertext as they do not require padding. Unfortunately Microsoft opted not to include counter mode in .NET. You could use CFB mode.

You could also decide to implement counter mode using ECB if you require parallel encryption (in the comments below the question). Generally AES is so fast nowadays that parallelism is not required. Implementing a statically sized counter and CTR buffer should pale in comparison with creating the multithreaded code.


This is incorrect and may cause an issue:

int read = cryptoStream.Read(buffer, 0, inputencdec.Length);

you should of course put in buffer.length, not inputencdec.length. The use of a buffer is to store data in a buffer, by reading up to buffer.length bytes per loop iteration.

This is incorrect as well:

plainStream.Write(buffer, totalRead, read);

the problem is that totalRead should be the offset in the buffer, not the offset within the stream. You're reading into offset 0 of the buffer, so you should start writing from offset 0 as well.


You could also create a MemoryStream for the plaintext, wrap it with a CryptoStream using a decryptor, and then write the ciphertext all in one go. There is no need for the encryption / decryption to use a different scheme, as far as I can see. You seem to keep all the plaintext / ciphertext in memory anyway.


Notes:

  • for CBC mode the IV should be random; it is often prefixed to the ciphertext and removed and used by the decryptor;
  • keys and IV's should consist of random bytes; they should not be strings.
Maarten Bodewes
  • 90,524
  • 13
  • 150
  • 263