2

I have a server/client system, which encrypts images on the server (python) and decrypts them on the client (c#). The cryptography part is working perfectly, except for trying to decrypt info which is several-blocks long (for example, an image, and not a "Hello World" string).

So, when I try to decrypt encrypted images via a CryptoStream - sometimes it works, and for some reason - sometimes it doesn't.

This is the decryption process of the image:

public static byte[] DecryptBytesFromBytes(byte[] encryptedImage, byte[] key)
        {
            byte[] decryptedImage;

            // Create an Aes object with the specified key and IV.
            using (Aes aesAlg = Aes.Create())
            {
                aesAlg.Key = key;
                aesAlg.Padding = PaddingMode.Zeros;
                aesAlg.Mode = CipherMode.CBC;

                byte[] IV = new byte[16];
                byte[] cipherBytes = new byte[encryptedImage.Length - IV.Length];

                Array.Copy(encryptedImage, IV, IV.Length);
                Array.Copy(encryptedImage, IV.Length, cipherBytes , 0, cipherBytes.Length);

                aesAlg.IV = IV;

                // Create a decryptor to perform the stream transform.
                ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV);

                using (var input = new MemoryStream(cipherBytes))
                using (var output = new MemoryStream())
                {
                    using (var cryptStream = new CryptoStream(input, decryptor, CryptoStreamMode.Read))
                    {
                        var buffer = new byte[1024];
                        var read = cryptStream.Read(buffer, 0, buffer.Length);
                        while (read > 0)
                        {
                            output.Write(buffer, 0, read);
                            read = cryptStream.Read(buffer, 0, buffer.Length); // Error here
                        }
                        decryptedImage= output.ToArray();
                    }
                }
                return decryptedImage;
            }

If it helps, I get the same error even when doing:

cryptStream.CopyTo(output);

This is the python code for encryption:

@staticmethod
def pad(s):
    return s + b"\0" * (AES.block_size - len(s) % AES.block_size)

def encrypt(self, message):
    message = self.pad(message)
    iv = Random.new().read(AES.block_size)
    cipher = AES.new(str.encode(self.key), AES.MODE_CBC, iv)
    return iv + cipher.encrypt(message)

The Exception

Sometimes I get this error: System.ArgumentException: Offset and length were out of bounds for the array or count is greater than the number of elements from index to the end of the source collection.

The full stacktrace:

at System.Buffer.BlockCopy (System.Array src, System.Int32 srcOffset, System.Array dst, System.Int32 dstOffset, System.Int32 count) [0x00097] in <d4a23bbd2f544c30a48c44dd622ce09f>:0 
  at Mono.Security.Cryptography.SymmetricTransform.InternalTransformBlock (System.Byte[] inputBuffer, System.Int32 inputOffset, System.Int32 inputCount, System.Byte[] outputBuffer, System.Int32 outputOffset) [0x000b0] in <d4a23bbd2f544c30a48c44dd622ce09f>:0 
  at Mono.Security.Cryptography.SymmetricTransform.FinalDecrypt (System.Byte[] inputBuffer, System.Int32 inputOffset, System.Int32 inputCount) [0x00020] in <d4a23bbd2f544c30a48c44dd622ce09f>:0 
  at Mono.Security.Cryptography.SymmetricTransform.TransformFinalBlock (System.Byte[] inputBuffer, System.Int32 inputOffset, System.Int32 inputCount) [0x0002e] in <d4a23bbd2f544c30a48c44dd622ce09f>:0 
  at System.Security.Cryptography.CryptoStream.Read (System.Byte[] buffer, System.Int32 offset, System.Int32 count) [0x002e3] in <d4a23bbd2f544c30a48c44dd622ce09f>:0 
  at Project.Crypto.DecryptBytesFromBytes (System.Byte[] encryptedImage, System.Byte[] key) [0x000b9] in C:\Users\user\Desktop\Project\Crypto.cs:129 

Note that Project.Crypto.DecryptBytesFromBytes is the decryption function.

Does anybody have any idea why it happens, and how can I fix it? Let me know if more information is needed.

This is what I found in the documentation of the function Read():

// Exceptions:
//   T:System.ArgumentException:
//     Thesum of the count and offset parameters is longer than the length of the buffer.

By the way, I use CBC mode and padding of zeros.

I would like to clarify one last thing - I do this whole process just so I could take encrypted bytes, and turn them into decrypted bytes. If there is another way to decrypt bytes into bytes in c#, please let me know.

prodev1
  • 53
  • 7
  • Do you `.FlushFinalBlock()` when you encrypt the file? –  Jun 04 '20 at 11:32
  • Nope. It is a bit complicated to explain, but the files are encrypted with python (on a server). What does `FlushFinalBlock()` when encrypting? @JQSOFT – prodev1 Jun 04 '20 at 11:34
  • I see. You should do then. [Here](https://learn.microsoft.com/en-us/dotnet/api/system.security.cryptography.cryptostream.flushfinalblock?view=netcore-3.1)... –  Jun 04 '20 at 11:37
  • Could you give me further information? Where should I do it? what does it actually do? @JQSOFT – prodev1 Jun 04 '20 at 11:38
  • The last line. Just before closing and disposing the stream or the last line in the `using {..}` block if you are using it. –  Jun 04 '20 at 11:41
  • @JQSOFT but the error occures before the last line. Is it ok? – prodev1 Jun 04 '20 at 11:42
  • Anyways, I get `System.NotSupportedException: FlushFinalBlock() method was called twice on a CryptoStream. It can only be called once.` – prodev1 Jun 04 '20 at 11:44
  • Excuse me, but are you talking about the encryption process? Because again, I use python for encryption. – prodev1 Jun 04 '20 at 11:45
  • The last line in the _Encryption_ routine buddy. You need to fill the missing length. If you don't write it correctly then you won't read it. –  Jun 04 '20 at 11:46
  • PresidentJamesK.Polk thank you for the help. @JQSOFT if you are talking about padding empty space, I actually do it with null bytes "\0". – prodev1 Jun 04 '20 at 11:49
  • @JQSOFT using C# for the decryption. Sorry for the confusion. I'd like to remind, again, that sometimes the decryption works, and sometimes it doesn't - the description of the exception seems like something very trivial, but I can't manage to get around it. – prodev1 Jun 04 '20 at 11:50
  • @JQSOFT may be right about this: it might be impossible to debug this *without* seeing the encryption code also. – President James K. Polk Jun 04 '20 at 11:51
  • @PresidentJamesK.Polk my bad, updated. Thank you for the help. – prodev1 Jun 04 '20 at 11:53
  • And that's using pycryptodome? – President James K. Polk Jun 04 '20 at 11:54
  • @PresidentJamesK.Polk It uses a module called `Crypto`, which I think is a different name for pycryptodome. Not sure tho. – prodev1 Jun 04 '20 at 11:56
  • It could be either pycrypto or pycryptodome. pycrypto is no longer maintained, pycryptodome is a fork of pycrypto that is well maintained. – President James K. Polk Jun 04 '20 at 11:59
  • I don't see how that exception is possible for that code. Is this really the actual code that is throwing the exception? – President James K. Polk Jun 04 '20 at 12:15
  • @PresidentJamesK.Polk Yep. It doesn't make sense. According to the exception's description, buffer.Length + 0 is bigger than buffer.Length ... – prodev1 Jun 04 '20 at 12:19
  • @PresidentJamesK.Polk In my opinion, there is a problem with the null ("/0") padding. Seems like sometimes it can't be read. Do u have any idea how to debug this? – prodev1 Jun 04 '20 at 13:46
  • Please print out the full stacktrace. If I'd had to guess either you're not receiving the full ciphertext **or** the Python code only pads with zeros if required and C# expects the zero padding to be present even if the end of the plaintext is already on a block boundary. But without enough code that's just guessing; we cannot debug with the amount of code provided. – Maarten Bodewes Jun 04 '20 at 20:34
  • Almost forgot: zero padding is non-deterministic if the plaintext might end with zero bytes. Furthermore, using just CBC over a network connection is criminally insecure. You should use transport security (i.e. TLS). – Maarten Bodewes Jun 04 '20 at 20:36
  • @MaartenBodewes Thank you for your help. Could you explain please about the consequences of using CBC only? By the way, I updated the question - added some more code to the c# section and added the full stacktrace. Thanks a lot! – prodev1 Jun 04 '20 at 21:38

0 Answers0