我们有一个套接字服务器,它需要将加密的二进制文件传输到连接的客户端。当请求到达时,文件需要加密,最好不要先在磁盘上制作文件的加密副本。
由于我们使用异步套接字 API,因此无法使用 Sockets.NetworkStream。相反,我们需要使用带有 byte[] 缓冲区的 Socket.BeginSend() 作为输入。
一种看似直接的可能性是将 CryptoStream 与 MemoryStream 一起用作加密内容的目的地。MemoryStream 本身将使用 byte [] 缓冲区作为自己的数据存储库。
例如:
int blockSizeBytes = 1024 * 64;
byte [] plainData = new byte [blockSizeBytes];
byte [] encData = new byte [blockSizeBytes];
MemoryStream memory = new MemoryStream( encData );
ICryptoTransform encryptor = ... any ***CryptoServiceProvider.CreateEncryptor();
CryptoStream csEnc = new CryptoStream( memory, encryptor, CryptoStreamMode.Write );
可以一次读取一个文件并加密一个缓冲区,然后通过套接字将其发送到客户端。例如:
Socket clientSocket = ...; // connected peer.
int bytesRead = 0;
FileStream streamIn = new FileStream( strInputFile, FileMode.Open );
do
{
bytesRead = streamIn.Read( plainData , 0, blockSizeBytes );
if (bytesRead > 0)
{
csEnc.Write( plainData , 0, bytesRead ); // Write to crypto stream
// At this point the underlying byte array encData will hold the most recently
// encrypted buffer of data.
// Ideally we would send the encData buffer over the socket to the client via
// the following pseudo-code:
// 1) How can we determine the precise number of encoded bytes to send?
clientSocket.BeginSend( encData, 0, bytesRead, ... /* other params */ );
...
memory.Seek( 0, SeekOrigin.Begin ); // Reset memory stream back to start
}
}
while (bytesRead > 0);
streamIn.Close(); // close intput file stream
outEnc.FlushFinalBlock(); // Deal with padding, etc.
// Send the final buffer with all the necessary padding to the client.
// 2) Again, how can we determine the exact number of encoded bytes to send?
clientSocket.BeginSend( encData, 0, ??how-many-bytes??, ... );
outEnc.Close();
出于测试目的,我们将编码的缓冲区写入文件而不是套接字。尝试解密生成的文件时,会引发以下异常:CryptographicException:要解密的数据长度无效。
从上面的项目 1) 和 2) 中可以看出,我们不知道要传输到客户端(或保存到文件)的编码字节的精确数量。我们在 FlushFinalBlock() 之后尝试将 memory.Position 作为缓冲区大小,但没有成功。
请注意,当 CryptoStream 使用 FileStream 作为其输出时,即既不使用 MemoryStream 也不使用 byte[] 缓冲区时,生成的文件被正常加密,然后成功解密。不过,我们的目标是能够在没有输出流的情况下直接写出加密的 byte[] 缓冲区。
如果带有 byte[] 缓冲区的 MemoryStream 不可行,是否还有其他替代方法可以增量加密缓冲区并将它们转发到例如套接字上?