3

I have a program that uses BinaryReader and BinaryWriter to send string, int and byte[] messages over the network.

The order and content of the messages is significant for the flow of the execution on both server and client, but the duration is never long.

Now I'm trying to encrypt everything.

This is the new wrapper that I have around the actual code:

using encReaderStream = CryptoStream(clientStream, myAES.CreateDecryptor(), CryptoStreamMode.Read),\
      encWriterStream = CryptoStream(clientStream, myAES.CreateEncryptor(), CryptoStreamMode.Write),\
      enc_reader = BinaryReader(encReaderStream),\
      enc_writer = BinaryWriter(encWriterStream):
          ....

This example is boo code, but it should be intuitively equivalent to C# in this instance.

What happens now is that the server gets the first encrypted message correctly with enc_reader.ReadString(), and answers with enc_writer.Write("Accepted"). But the client never gets the answer.

I have tested if the order of the messages is significant, and it is. If I instead start by sending a string from the server, then the client gets it, but if I continue to send messages, I will soon get into the same situation.

I have some idea that CryptoStream might be responsible for not cooperating properly with BinaryReader/BinaryWriter, but I don't know how to sort out this mess in a good way.

My server has a lot of functions that just expects a BinaryReader and a BinaryWriter, and it would be super convenient if they could work like before.

EDIT:

I've also replicated the situation in a small C# project here, using the the mentioned implementation of AES with CTR mode.

Steinbitglis
  • 2,482
  • 2
  • 27
  • 40

1 Answers1

1

You can't flush a block cipher in the middle of a block because those bytes are not ready from an algorithmic standpoint. They are not determined.

Probably, the best fix is to use a stream cipher. .NET has poor built-in support for that. Pull in a library that implements AES in counter mode.

Be aware that without using authenticated encryption (and it does not look like you are going it) attackers can edit the data although they cannot read it. Use AES-GCM to mitigate.


Later we found out that the CTR mode library you are using is broken. Use this:

public int InputBlockSize { get { return 1; } }
public int OutputBlockSize { get { return 1; } }
usr
  • 168,620
  • 35
  • 240
  • 369
  • The symmetric keys are somewhat temporary and hidden behind a pre-shared asymmetric keys. I'm not a security expert, I don't know if it's vulnerable or not. – Steinbitglis Sep 26 '15 at 23:53
  • What do you think of this implementation? https://gist.github.com/hanswolff/8809275 – Steinbitglis Sep 27 '15 at 01:10
  • I'm not qualified to audit this code. I'd pick the code from the web that seems to be used most often... Thankfully counter mode is not hard to implement. For AES-GCM there is a solid implementation that seems to come from Microsoft. – usr Sep 27 '15 at 09:54
  • Now I've tried both RijndaelManaged, setting its cipher mode to CFB and feedback size to 8 bits, and I've tried AES128 Counter mode... safe or not, they both had the same characteristics in my program. The first message gets through, the second doesn't. Maybe it's more related to BinaryReader than actual encryption? – Steinbitglis Sep 27 '15 at 12:06
  • OK, the encryption issue was definitively a problem that needed to be solved. There is another. Something in the chain is not flushed. Can you post more complete code? You also can use the debugger to peek into object internals and discover data that is not flushed. – usr Sep 27 '15 at 12:09
  • Ah! Some new information.... the first message doesn't actually get through... until the sender closes the stream due to timeout.... that's when the first message actually gets through. – Steinbitglis Sep 27 '15 at 12:09
  • Maybe your socket code is broken. Most socket code is broken... Post more. – usr Sep 27 '15 at 12:10
  • Code posted.... the 'New' message gets through, when the client's ReadString hits its timeout. I guess 'New' gets through because the stream is closed at that time. – Steinbitglis Sep 27 '15 at 12:34
  • Went back to RijndaelManaged, FeedbackSize 8, Mode CFB, Padding None (no padding is new). Now I get this: "CryptographicException: invalid block length" – Steinbitglis Sep 27 '15 at 13:09
  • Using a block cipher cannot work because it buffers data by nature. Btw, why are you sending the key in the clear? That makes the encryption useless. – usr Sep 27 '15 at 13:27
  • That comment was not quite accurate. The problem is not the block cipher, it is the blocking mode of operation. – usr Sep 27 '15 at 13:34
  • I'm actually trying to find a usable stream cipher. According to this thread, http://stackoverflow.com/questions/11776227/c-sharp-aes-128-cfb-error, Rijndael should work as a stream cipher in this case. I also thought that the AES block mode implementation would suffice, but it was incomplete, and dind't allow 'ReadString' to return immediately as I had hoped. – Steinbitglis Sep 27 '15 at 13:44
  • No, the key is not in the clear, even in this example. – Steinbitglis Sep 27 '15 at 13:45
  • Why are you still working on finding an algorithm? You already had a working one: AES in CTR mode. Not sure what properties CFB with feedbacksize 8 has. That sounds dangerous. There's probably a reason the feedback size normally is much higher. – usr Sep 27 '15 at 13:49
  • When I first tried the code that I linked here, it wasn't working because CryptoStream was expecting an IV etc. etc. And when I had patched it up to run.... it had the same issue as the others. But I don't mind making another go at it. That is.... this code here https://gist.github.com/hanswolff/8809275 – Steinbitglis Sep 27 '15 at 13:53
  • That's because there are two bugs: The blocking cipher and something else. – usr Sep 27 '15 at 13:56
  • Ok, I'll be digging a little deeper. Thanks so far! – Steinbitglis Sep 27 '15 at 14:01
  • I don't know quite what to look for, but I managed to replicate the exact same situation in a new, small c# project http://fredrik1.com:22080/download_res/CryptoStreamDebug.zip – Steinbitglis Sep 27 '15 at 16:57
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/90738/discussion-between-steinbitglis-and-usr). – Steinbitglis Sep 27 '15 at 17:11