我决定在我的服务中实现文件传输的加密。之前的文件传输没有加密,它们以完全相同的字节数完美地发送和接收。
现在我已经在混合中引入了asymmetrical
和symmetrical
加密,以便在数据通过TCP协议时加密数据。我使用asymmetrical
进行初始握手,将symmetrical
密钥传递给由asymmetric
公钥加密的另一方。从那时起,文件的接收者定期呼叫发送者,并且发送者生成新的initialization vector
,使用symmetric
密钥加密数据,并将其发送以由接收者使用解密IV和相同的symmetric
密钥。
我使用的块大小是2mb,这样生成的块的字节大小(最后一个变化的块除外)是2097152
。当AES使用PaddingMode.PKCS7
和CipherMode.CBC
加密此文件时,生成的字节大小为2097168
。它在加密过程中获得了大约16个字节。
现在我最初认为这是我的问题所在,但是当我在接收端解密数据时,它会回到2097152
字节长度并将其写入文件。我已经向自己证明它确实加密和解密了数据。
在足够小的文件上,从原始文件到发件人的文件大小似乎完全相同。但是,当我升级到更大的文件大小时,存在一种不确定性。在大小为26,246,026 bytes
的视频文件(来自Windows 7安装的Wildlife.wmv)上,我收到了26,246,218 bytes
的完成转移。
为什么会出现这种尺寸差异?我在这里做错了什么?
这是我的一些代码。
对于我的加密,我使用以下类加密或解密,以字节数组的形式返回结果。
public class AesCryptor
{
public byte[] Encrypt(byte[] data, byte[] key, byte[] iv)
{
using (SymmetricAlgorithm aes = new AesManaged())
{
aes.Key = key;
aes.IV = iv;
aes.Padding = PaddingMode.PKCS7;
aes.Mode = CipherMode.CBC;
using (ICryptoTransform encryptor = aes.CreateEncryptor(key, iv))
{
return Crypt(data, key, iv, encryptor);
}
}
}
public byte[] Decrypt(byte[] data, byte[] key, byte[] iv)
{
using (SymmetricAlgorithm aes = new AesManaged())
{
aes.Key = key;
aes.IV = iv;
aes.Padding = PaddingMode.PKCS7;
aes.Mode = CipherMode.CBC;
using (ICryptoTransform decryptor = aes.CreateDecryptor(key, iv))
{
return Crypt(data, key, iv, decryptor);
}
}
}
private byte[] Crypt(byte[] data, byte[] key, byte[] iv, ICryptoTransform transform)
{
using (MemoryStream memoryStream = new MemoryStream())
{
using (CryptoStream cryptoStream = new CryptoStream(memoryStream, transform, CryptoStreamMode.Write))
{
cryptoStream.Write(data, 0, data.Length);
cryptoStream.FlushFinalBlock();
}
return memoryStream.ToArray();
}
}
}
文件的发件人正在使用此代码加密数据(在私有对称密钥握手之后)(以及与实际加密过程无关的更多内容。请注意chunkedFile.NextChunk()。调用正在为我执行文件分块的类的方法,返回2mb块大小,除非最终大小更小。
byte[] buffer;
byte[] iv = new byte[symmetricEncryptionBitSize / 8];
using (var rngCrypto = new RNGCryptoServiceProvider())
rngCrypto.GetBytes(iv);
AesCryptor cryptor = new AesCryptor();
buffer = cryptor.Encrypt(chunkedFile.NextChunk(), symmetricPrivateKey, iv);
下面的代码是文件接收者使用的代码(不是全部代码,这与解密数据有关)。数据正被写入文件流(writer
)。
FileMessage message = hostChannel.ReceiveFile();
moreChunks = message.FileMetaData.MoreChunks;
UpdateTotalBytesTransferred(message);
writer.BaseStream.Position = filePosition;
byte[] decryptedStream;
// Copy the message stream out to a memory stream so we can work on it afterwards.
using (var memoryStream = new MemoryStream())
{
message.ChunkData.CopyTo(memoryStream);
decryptedStream = cryptor.Decrypt(memoryStream.ToArray(), symmetricPrivateKey, message.FileMetaData.InitializationVector);
}
writer.Write(decryptedStream);
顺便说一句,如果需要,NextChunk是一个非常简单的方法。
public byte[] NextChunk()
{
if (MoreChunks) // If there are more chunks, procede with the next chunking operation, otherwise throw an exception.
{
byte[] buffer;
using (BinaryReader reader = new BinaryReader(File.OpenRead(FilePath)))
{
reader.BaseStream.Position = CurrentPosition;
buffer = reader.ReadBytes((int)MaximumChunkSize);
}
CurrentPosition += buffer.LongLength; // Sets the stream position to be used for the next call.
return buffer;
}
else
throw new InvalidOperationException("The last chunk of the file has already been returned.");
}
编辑:似乎对于每个传输的块,因此每次加密,我的文件大小增加了16bytes。对于非常小的文件大小,这不会发生。
答案 0 :(得分:1)
我解决了这个问题。
事实证明我在消息数据中发送了加密块数据的chunkLength
。因此,对于我发送的每个块,即使我解密并写入了正确的filedata,我也按照加密数据的长度推进了流的位置。这意味着每次我解密时,当传输超过1个块时(这就是为什么只有1个块大小的小文件没有问题)我在文件大小上添加了16个字节。
帮助我的人可能无法解决这个问题,因为我没有在客户端或服务器端包含所有数据来查看。但幸好我自己设法回答了。
在发件人方面,我正在创建我的FileMessage。
FileMessage message = new FileMessage();
message.FileMetaData = new FileMetaData(chunkedFile.MoreChunks, chunkedFile.ChunkLength, chunkedFile.CurrentPosition, iv);
message.ChunkData = new MemoryStream(buffer);
如果你看到FileMetaData
构造函数的第二个参数,我传入的chunkedFile.ChunkLength
应该是块的长度。我在加密的块数据上执行此操作,导致发送不正确的块长度。
另一方面,客户正在接收这些额外信息。如果你看近尾,你会看到代码filePosition += message.FileMetaData.ChunkLength;
。我正在使用那个错误的chunkLength
来提升档案位置。事实证明,甚至不需要设置streamPosition。
using (BinaryWriter writer = new BinaryWriter(File.OpenWrite(fileWritePath)))
{
writer.BaseStream.SetLength(0);
while (moreChunks)
{
FileMessage message = hostChannel.ReceiveFile();
moreChunks = message.FileMetaData.MoreChunks;
UpdateTotalBytesTransferred(message);
writer.BaseStream.Position = filePosition;
byte[] decryptedStream;
// Copy the message stream out to a memory stream so we can work on it afterwards.
using (var memoryStream = new MemoryStream())
{
message.ChunkData.CopyTo(memoryStream);
Debug.WriteLine("Received Encrypted buffer Length: " + memoryStream.Length);
decryptedStream = cryptor.Decrypt(memoryStream.ToArray(), symmetricPrivateKey, message.FileMetaData.InitializationVector);
Debug.WriteLine("Received Decrypted buffer Length: " + decryptedStream.Length);
}
writer.Write(decryptedStream);
TotalBytesTransferred = message.FileMetaData.FilePosition;
filePosition += message.FileMetaData.ChunkLength;
}
OnTransferComplete(this, EventArgs.Empty);
StopSession();
}
这么简单的错误,但根本没有快速向我跳过。