How can an AES Encrypted StreamWriter Send data before the connection closes?

Andrew Cover 0 Reputation points
2024-07-03T16:18:19.5466667+00:00

Given this Reader/Server side code:

$Listener = [System.Net.Sockets.TcpListener]61855
$Listener.Start()
$Client = $Listener.AcceptTcpClient()
$Stream = $Client.GetStream()
[byte[]]$key = (
	0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
	0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,
	0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,
	0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f
)
$Aes = [System.Security.Cryptography.Aes]::Create()
$Aes.Key = $key
$IV = New-Object byte[] -ArgumentList $Aes.IV.Length
$BytesToRead = $Aes.IV.Length
$Stream.Read($IV,0,$BytesToRead)
$Aes.IV = $IV
$ReadMode = [System.Security.Cryptography.CryptoStreamMode]::Read
$EncryptedStream = New-Object System.Security.Cryptography.CryptoStream -ArgumentList $Stream,
	$Aes.CreateDecryptor($key, $IV),
	$ReadMode

$EReader = New-Object System.IO.StreamReader($EncryptedStream)
do {
	$EReader.Readline()
} while (!$EReader.EndOfStream)

and this Writer/Client side code:

$Connection = New-Object System.Net.Sockets.TcpClient("localhost",61855)
$Stream = $Connection.GetStream()
[byte[]]$key = (
	0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
	0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,
	0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,
	0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f
)
$Aes = [System.Security.Cryptography.Aes]::Create()
$Aes.Key = $key
$Stream.Write($Aes.IV,0,$Aes.IV.Length)
$WriteMode = [System.Security.Cryptography.CryptoStreamMode]::Write
$EncryptedStream = New-Object System.Security.Cryptography.CryptoStream -ArgumentList $Stream,
	$Aes.CreateEncryptor(),
	$WriteMode
$EWriter = New-Object System.IO.StreamWriter($EncryptedStream)
for ($count = 0; $count -lt 128; $count ++) {
	$EWriter.WriteLine("ab")
	$EWriter.Flush()
}

The Reader side never gets any data until the Writer side closes the connection. In my search for an answer I have found that due to using AES encryption the CryptoStream will not send any data when a block is incomplete. So I am using WriteLine with a two character string "ab". This should produce four bytes of data to the CryptoStream, specifically

  • 0x61 "a"
  • 0x62 "b"
  • 0x0d CARRIAGE RETURN
  • 0x0a LINE FEED

With four bytes of data being written to the CryptoStream each time I flush the data, that should mean that it reaches the 128 Bit block size after the fourth line, and I should have a total of 32 blocks of 128 Bits sent to the CryptoStream But the data is never sent until I call:

$EWriter.Close()

Then the reader gets all lines of data immediately. I am sending 512 total bytes in this code, so even if I misunderstood the block size of 128 Bits and it should be 128 Bytes I am still sending 4 complete blocks. I have also tried this code with the string "a" to provide an offset if the padding were to confound my calculation of what bytes are being sent.

Additionally if I set the LeaveOpen: $true attribute on the CryptoStream during creation, closing the EWriter does not send the data, I still have to call Close() on the CryptoStream for the data to send. I would like to be able to leave the connection open to have a bit of bidirectional encrypted communication without having to establish new connections each time.

PowerShell
PowerShell
A family of Microsoft task automation and configuration management frameworks consisting of a command-line shell and associated scripting language.
2,323 questions
0 comments No comments
{count} votes