Rijndael CryptoStream, NetworkStream, and Padding

  • Thread starter Thread starter Nicholas Holder
  • Start date Start date
N

Nicholas Holder

A client creates a connection to the server using the TCPListener/Client
classes and transfers data via a NetworkStream. When the client connects,
the server creates a process and redirects its StandardOut to traverse back
over the network to the client. I want to encrypt this data and the code I
have is below. However, occasionally during processing, I receive an
exception stating the PKCS7 padding is invalid and cannot be removed. I have
searched high and low for this. While I have found some interesting
discussions, I have yet to find a clear answer. Please help. Thanks!

'// Server code: Called after receiving a command from the client.
'// Encrypts data and returns it
Private Sub OnCompletedReadStdOut(ByVal ar As IAsyncResult)

If ar Is Nothing Then Return

Try
Dim intBytesRead As Integer = StreamStdOut.EndRead(ar)

If intBytesRead > 0 Then
Dim s As String = Encoding.ASCII.GetString(BufferStdOut,
0, intBytesRead)

If s <> strLastCommand Then
'// Create a memory stream and encrypt data to it
Dim ms As New MemoryStream
Dim cs As New CryptoStream(ms,
aes.CreateEncryptor(aes.Key, aes.IV), CryptoStreamMode.Write)

'BufferStdOut is dimensioned to 204800.
'No need for this size. 1024 would suffice but the
problem
'happens less frequently the larger the buffer.
cs.Write(BufferStdOut, 0, intBytesRead)
cs.FlushFinalBlock() 'error occurs here **

'// get the encrypted data to send
Dim bytData(ms.Length) As Byte
ms.Position = 0
intBytesRead = ms.Read(bytData, 0, ms.Length)
cs.Close()

Stream.Write(bytData, 0, bytData.Length)

bytData = Nothing
cs.Clear()
cs = Nothing
ms = Nothing
End If

'// reinitialize the asyncronous callback
StreamStdOut.BeginRead(BufferStdOut, 0,
BufferStdOut.Length, CallBackStdOut, Nothing)
End If

Catch ex As Exception
'// Return error info
End Try
End Sub

'// Client code: Called after receiving data from the server.
'// Decrypts and displays data
Private Sub OnCompletedRead(ByVal ar As IAsyncResult)
If ar Is Nothing Then Shutdown()

Try
Dim intBytesRead As Integer = Stream.EndRead(ar)

If intBytesRead > 0 Then
'// Decrypt data
Try
'// Put buffer into memory and create a decryptor
Dim ms As New MemoryStream
Dim cs As New CryptoStream(ms,
aes.CreateDecryptor(aes.Key, aes.IV), CryptoStreamMode.Write)

'bytBuffer is the same size as BufferStdOut (mentioned
above)
cs.Write(bytBuffer, 0, intBytesRead - 1)
cs.FlushFinalBlock() 'error occurs here **

'// decrypt the data
Dim bytData(ms.Length) As Byte
ms.Position = 0
intBytesRead = ms.Read(bytData, 0, ms.Length)
cs.Close()

If intBytesRead > 0 Then
'// Translate the data to the string and display
Dim s As String = Encoding.ASCII.GetString(bytData,
0, intBytesRead)

Console.Write(s)
End If

bytData = Nothing
cs.Clear()
cs = Nothing
ms = Nothing
Catch ex As Exception
'// Return Error Info
Console.WriteLine(ex.ToString)
End Try

'// Reinitialize the callback
Stream.BeginRead(bytBuffer, 0, bytBuffer.Length, callback,
Nothing)
Else
'// The connection was terminated by the server
Shutdown()
End If
Catch ex As Exception
'// The connection was terminated by the server
Shutdown()
End Try
End Sub
 
Nicholas Holder said:
A client creates a connection to the server using the TCPListener/Client
classes and transfers data via a NetworkStream. When the client connects,
the server creates a process and redirects its StandardOut to traverse back
over the network to the client. I want to encrypt this data and the code I
have is below. However, occasionally during processing, I receive an
exception stating the PKCS7 padding is invalid and cannot be removed. I have
searched high and low for this. While I have found some interesting
discussions, I have yet to find a clear answer. Please help. Thanks!
Nicholas -

Most likely you are not receiving all of the encrypted data before
feeding it into the decryptor. With TCP there is no guarantee that all
of the data sent from a single Write() will be read by a single
Read(). You must account for that in your client code.

Since you already know the size of the data being sent, my
recommendation would be to send the size value before the actual data.
On the client side, read the size value, then loop on the Read()
methods until all of the data has been read. Then you know you have
all of the data to feed into the decryptor.

Hope this helps solve your problem.

Rich Blum
Author of "C# Network Programming" (Sybex)
http://www.sybex.com/sybexbooks.nsf/Booklist/4176
 
Back
Top