Read the special stream without knowing the number of bytes

Before you go and say, use Jon Skeet's answer , I can't. I'm using this thread , which works great in the beginning, but now I am having a little problem. I am now at a point where I do not know how much data I expect, so I thought that I would use the Jon Skeet method, but unfortunately, it waits for packet = mPackets.Take() when all the packets have been read.

I have no idea how to fix this, the thread does what it should do (at the beginning), but, unfortunately, this is the case when I do not want it to do what it was created for ...

Should I try to rewrite the waitingstream or is there another readall method that will work better in my case?

I tried to return 0 when there were no more packages available (when I wanted it to read everything and not wait), but then it throws an IO end of stream exception .

I am really in trouble here, I understand that I dug a deep hole for myself ...

So far, I have not been able to find a better solution than to subtract the TLS and GCM IV and MAC header from the total length (as indicated below). This is great for the 1 package I am using now, but not to boast of future cipher suites.


Some context why I do this:
I use https://github.com/bcgit/bc-csharp to create TLS-based encryption, however due to restrictions I cannot assign a TCP stream to it, all I get is a string from the TCP layer, I cannot provide him with a propper TCP stream.

I use mockPskTlsServer and the client , and I created it like this:

 WaitingStream mStdin = new WaitingStream(); WaitingStream mStdout = new WaitingStream(); CryptoPskTlsClient mServer = new CryptoPskTlsClient(null); SecureRandom secureRandom = new SecureRandom(); TlsClientProtocol TlsProtocol = new TlsServerProtocol(Stdin, Stdout, secureRandom); TlsProtocol.Connect(mServer); 

This works fine, I also added an event to the wait thread, which fires when it is output to the thread. Thus, I could receive messages with several handshakes when they were created.

All this works great, it can be done better (less ... hacked?), But it does what it should do.

I know how to make it work, but it's HACK, and I'm looking for an elegant way to do it. Here is a sample code for one of these HACKS:

 public override string DecryptData(string ciphertext) { byte[] ciphertextBuff = ASCIIEncoding.Default.GetBytes(ciphertext); mStdin.Write(ciphertextBuff, 0, ciphertextBuff.Length); Stream tlsStream = mServerProtocol.Stream; byte[] plaintextBuffer = new byte[ciphertextBuff.Length - 29];//filthy HACK 29 bytes bij AES-GCM want TLS packet = 5, GCM IV = 8, GCM-MAC = 16 totaal = 29. Streams.ReadFully(tlsStream, plaintextBuffer); string plaintext = ASCIIEncoding.Default.GetString(plaintextBuffer); return plaintext; } 

or by adding the length of unencrypted text in x reserved bytes to the TLS packet and receiving these bytes before decryption.

but, as you can clearly see from the code example, the buffer in the read method should completely be the length of the bytes I want to extract, it may be less than the stream, but it cannot be more, because then it will wait indefinitely.

When I talk about methods like readall and ReadFully I mean these methods

+7
c # stream ssl bouncycastle
source share
2 answers

all i get is a string from the TCP layer

This is certainly a fatal flaw in your attempts to do this job. The implicit thing you are trying to do is that the data sent over the TCP connection is encrypted with TLS. Which produces highly random byte values, possibly any value from 0 to 255. The data packet that you receive from the socket call Read () is a byte [], not a string.

Converting byte [] to string requires the use of the .NET Encoding class. There are many varieties of it, and the stock ones are ASCIIEncoding, UnicodeEncoding, UTF8Encoding. And a bunch of custom ones designed to work with a specific code page, you get them using the Encoding constructor (int codePage).

We donโ€™t know that encoding is used by the โ€œTCP layerโ€, which you probably need to work with, is UTF8, but that means that it will always generate corrupted data when it is asked to convert byte [] with encrypted content. Some byte values โ€‹โ€‹do not have a corresponding Unicode codeword. Does the encoding object solve this problem by generating a character ? or as a replacement character. Whatever the value of Encoding.EncoderFallback. Some chances are that you can see them in the debugger, although the frequency is unpredictable.

In other words, encrypted data will inevitably be corrupted by these replacements. There is no workaround for this; you cannot do anything to restore the original byte [], because the content was lost by substitutions. This one should be occupied by lower levels, they either need to encode the contents of the byte [] on a string that can always convert (base64 is a standard solution), or it should stop converting the data into a string. You really need the raw byte [] to make this work.

+5
source share

Did you try to delete the input stream after recording it?

This should indicate an internal BlockingCollection<byte> of mStdIn , which will no longer enter. I'm not sure if this applies to your tlsStream though.

+1
source share

All Articles