I'm writing an app for sending and receiving AES encrypted files. I have two functions, one for sending:
public async Task SendFileAsync()
{
var buffer = new byte[1024];
using (Aes aesAlg = Aes.Create())
{
// tcpHandler.stream is a NetworkStream
using (ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV))
{
using (Stream fileStream = await selectedFile.OpenStreamForReadAsync())
{
using (CryptoStream csEncrypt = new CryptoStream(tcpHandler.stream, encryptor, CryptoStreamMode.Write, true))
{
while (stream.Position < selectedFileSize)
{
int nowRead = fileStream.Read(buffer, 0, buffer.Length); // read bytes from file
csEncrypt.Write(buffer, 0, nowRead); // write bytes to CryptoStream (which writes to NetworkStream)
}
}
}
}
}
await tcpHandler.stream.FlushAsync()
}
And one for receiving:
public async Task ReceiveFileAsync()
{
var buffer = new byte[1024];
BinaryFormatter formatter = new BinaryFormatter();
int messageLength = tcpHandler.ReadMessageLength();
int totalBytesRead = 0;
using (Aes aesAlg = Aes.Create())
{
// tcpHandler.stream is a NetworkStream
using (ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV))
{
using (var fileStream = await newFile.OpenStreamForWriteAsync())
{
using (CryptoStream csDecrypt = new CryptoStream(tcpHandler.stream, decryptor, CryptoStreamMode.Read, true))
{
while (totalBytesRead < messageLength)
{
// calculate how many bytes have to be read in this iteration
var toRead = Math.Min(buffer.Length, messageLength - totalBytesRead);
var nowRead = csDecrypt.Read(buffer, 0, toRead); // read bytes from CryptoStream
totalBytesRead += nowRead; // sum read bytes
fileStream.Write(buffer, 0, nowRead); // write decrypted bytes to file
}
}
}
}
}
}
The issue is that ReceiveFileAsync()
blocks itself on the last csDecrypt.Read(buffer, 0, toRead)
as if there wasn't enough data in csDecrypt
stream. However, when I close (kill the process) the sending application, the receiving application correctly receives the last buffer.
The same thing happens when I change the last parameter of using (CryptoStream csEncrypt = new CryptoStream(tcpHandler.stream, encryptor, CryptoStreamMode.Write, true))
to false
- it makes the CryptoStream close the base stream (tcpHandler.stream
) when it gets disposed.
If I do tcpHandler.stream.Close()
at the end of SendFileAsync()
it also helps.
In short, the last buffer I send doesn't get received until I close the sending NetworkStream (tcpHandler.stream
), either by closing/disposing it or closing the application.
I tried adding await tcpHandler.stream.FlushAsync()
as a last line of SendFileAsync()
, but it didn't help. Any ideas what should I do to fix this?
EDIT: Updated code with nested using
statements.