私のサービスでは、ファイル転送に暗号化を実装することにしました。これ以前のファイル転送は暗号化されておらず、まったく同じバイト数で問題なく送受信されていました。
これで、TCPプロトコルを通過するときにデータを暗号化するための暗号化をミックスに導入asymmetrical
しました。symmetrical
私は、公開鍵で暗号化された相手asymmetrical
に鍵を渡す最初のハンドシェイクを行うために使用します。それ以降、ファイルの受信者は定期的に送信者に電話をかけ、送信者は新しいを生成し、キーでデータを暗号化し、IVと同じキーを使用して受信者が復号化するために送信します。symmetrical
asymmetric
initialization vector
symmetric
symmetric
私が使用しているチャンクサイズは2mbであるため、生成されたチャンクのバイトサイズは、変化する最後のチャンクを除いて、です2097152
。AESがこのファイルをPaddingMode.PKCS7
とで暗号化するとCipherMode.CBC
、結果のバイトサイズは。になります2097168
。暗号化プロセス中に約16バイトが取得されます。
最初はこれが私の問題だと思っていましたが、受信側でデータを復号化すると、2097152
バイト長に戻ってファイルに書き込みます。私は、それが実際にデータを暗号化および復号化することを自分自身に証明しました。
十分に小さいファイルでは、元のファイルから送信者までのファイルサイズはまったく同じように見えます。ただし、ファイルサイズを大きくすると、不一致が生じます。サイズのビデオファイル(Windows 7インストールのWildlife.wmv)で26,246,026 bytes
、代わりに。の完了した転送を受信してい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);
以下のコードは、ファイルの受信者が使用するものです(すべてではありません。これは、データの復号化に関係するものです)。データはファイルstream(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.");
}
編集:転送されたすべてのチャンク、したがってすべての暗号化について、ファイルサイズが16バイト増えているようです。これは、ファイルサイズが極端に小さい場合には発生しません。