Wcf AES加密和解密导致文件与原始文件不同
我决定在我的服务中对文件传输实施加密。在此之前的文件传输是不加密的,发送和接收的字节数完全相同 现在,我在混合中引入了Wcf AES加密和解密导致文件与原始文件不同,wcf,encryption,aes,Wcf,Encryption,Aes,我决定在我的服务中对文件传输实施加密。在此之前的文件传输是不加密的,发送和接收的字节数完全相同 现在,我在混合中引入了非对称和对称加密,以在数据通过TCP协议时对其进行加密。我使用symmetric进行初始握手,将symmetric密钥传递给由asmmetric公钥加密的另一方。从那时起,文件的接收者定期调用发送者,发送者生成一个新的初始化向量,用对称密钥加密数据,并将其发送给接收者,由接收者使用IV和相同的对称密钥解密 我使用的块大小是2mb,因此生成的块的字节大小是2097152,但最后一个
非对称
和对称
加密,以在数据通过TCP协议时对其进行加密。我使用symmetric
进行初始握手,将symmetric
密钥传递给由asmmetric
公钥加密的另一方。从那时起,文件的接收者定期调用发送者,发送者生成一个新的初始化向量
,用对称
密钥加密数据,并将其发送给接收者,由接收者使用IV和相同的对称
密钥解密
我使用的块大小是2mb,因此生成的块的字节大小是2097152
,但最后一个块的大小不同。当AES使用PaddingMode.PKCS7
和CipherMode.CBC
加密此文件时,生成的字节大小为2097168
。它在加密过程中获得了大约16个字节
起初我认为这就是我的问题所在,但当我在接收端解密数据时,它返回到2097152
字节长度,然后我将其写入文件。我已经向自己证明,它确实对数据进行加密和解密
在足够小的文件上,从原始文件到发送者的文件大小似乎完全相同。但是,当我逐步增大文件大小时,会出现一种下降趋势。在一个大小为26246026字节
的视频文件(windows 7安装中的wivelet.wmv)上,我收到的是一个完成的传输,该传输的大小为26246218字节
为什么会有这种尺寸差异?我做错了什么
这是我的一些代码
对于我的加密,我使用下面的类来加密或解密,以字节数组的形式返回结果
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
)
顺便说一下,如果需要,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.");
}
编辑:似乎对于每一个传输的数据块,以及每一次加密,我都会获得16字节的文件大小。对于非常小的文件大小,这不会发生。我解决了这个问题 事实证明,我在消息数据中发送了加密区块数据的
chunkLength
。因此,对于我发送的每个区块,即使我解密并写入了正确的文件数据,我也会按照加密数据的长度推进流位置。这意味着每次我解密时,传输超过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();
}
这是一个简单的错误,但它并没有迅速向我扑来。这并不能解决您的密码问题,但您可以配置WCF来执行消息和传输(https)加密。Matthew-是的,但不幸的是,我使用了分块方法并将这些分块流式传输,因此我无法使用加密或可靠的消息传递。我必须使用自己的代码来实现这一点,并且不能依赖WCF。我发现流式传输比缓冲消息传输快得多,所以这就是我选择此路径的原因.
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();
}