次のコードは、マルチパート転送、クライアント側エンベロープ暗号化、およびAmazon KMSサービスを使用して、データ暗号化キーを処理します。マルチパーツブロックサイズは5MBです。最後の(部分的な)ブロックを転送する際AWS S3 .NETでKMSを使用するクライアント側の暗号化で問題が発生しました。最後の部分でProtocolViolationExceptionが発生しました
、及びIsLastPart
フラグがtrue
に設定されている場合のみ、UploadPart
の呼び出しが指示System.Net.ProtocolViolationException
を生成する:Bytes to be written to the stream exceed the Content-Length bytes size specified.
これは、コンテンツ長HTMLヘッダがあったことを示唆しています適切な整列のために暗号化エンジンによって最後の暗号ブロックに追加された必要な「パッドバイト」を反映するように更新されない。結果として、それらの最終バイトが追加されたとき、それらは指定されたContent-Lengthを超え、このエラーを生成しました。
IsLastPart
がないセット(すなわちfalse
を左)である場合、操作は成功したが、操作も失敗ダウンロードおよび復号化に依存します。
注:KmsAlgorithm
クラスは、AWS .NET SDKでは提供されていません。このクラスは別のスタックオーバーフローpostingから来ています.JMS SDKのようにエンベロープの暗号化をサポートするために、.NETバージョンのAWS SDKがKMSとS3の間にconnector classを提供しないためです。
クライアントサイドの暗号化とKMSの管理キーを使用して、複数パートのアップロードをS3に送信する適切な方法は何ですか?
static string bucketName = "*****************************";
static string keyName = "test.encrypted.bin";
static string uploadSourcePath = "c:\\temp\\test.bin";
static long partSize = 5 * 1024 * 1024;
static String uploadId = "";
static void Main(string[] args)
{
if (checkRequiredFields())
{
String cmkId = "************************************";
// Prepare our KMS client and kmsAlgorithm
using (AmazonKeyManagementServiceClient kmsClient = new AmazonKeyManagementServiceClient())
using (KMSAlgorithm kmsAlgo = new KMSAlgorithm(kmsClient, cmkId))
{
// Generate the encryption materials object with the algorithm object
EncryptionMaterials encryptionMaterials = new EncryptionMaterials(kmsAlgo);
// Now prepare an S3 crypto client
using (AmazonS3EncryptionClient cryptoClient = new AmazonS3EncryptionClient(encryptionMaterials))
{
// Initiate the multipart upload request specifying the bucket and key values
InitiateMultipartUploadResponse initResp = cryptoClient.InitiateMultipartUpload(
new InitiateMultipartUploadRequest()
{
BucketName = bucketName,
Key = keyName
});
uploadId = initResp.UploadId;
long fileLength = new FileInfo(uploadSourcePath).Length;
long contentLength = fileLength;
long bytesRemaining = fileLength;
List<PartETag> partETags = new List<PartETag>();
int partNumber = 0;
while (bytesRemaining > 0)
{
long transferSize = bytesRemaining > partSize ? partSize : bytesRemaining;
long partIndex = fileLength - bytesRemaining;
partNumber++;
UploadPartResponse resp =
cryptoClient.UploadPart(
new UploadPartRequest()
{
BucketName = bucketName,
Key = keyName,
FilePath = uploadSourcePath,
FilePosition = partIndex,
PartSize = transferSize,
PartNumber = partNumber,
UploadId = uploadId,
IsLastPart = transferSize < AwsS3FileSystemSample1.Program.partSize
});
partETags.Add(new PartETag(partNumber, resp.ETag));
bytesRemaining -= transferSize;
}
// Now complete the transfer
CompleteMultipartUploadResponse compResp = cryptoClient.CompleteMultipartUpload(
new CompleteMultipartUploadRequest()
{
Key = keyName,
BucketName = bucketName,
UploadId = initResp.UploadId,
PartETags = partETags
});
}
}
}
Console.WriteLine("Press any key to continue...");
Console.ReadKey();
}
ご迷惑をおかけして申し訳ございませんが、ご了承ください。
こんにちはAlton、私はあなたの実装に非常に感謝し、あなたが記述したとおりに正確に動作します。よくやった。ブロックチェーニングについては間違いなく、git hub上の.NET Transfer Utilityのソースコードを掘り下げた後、暗号化を使用しているときに複数パートの「並行」アップロードを明示的に防ぐことができます。 – user2107846
そのソースをさらに調べると、複数パートアップロードの最後のブロックでisLastPartフラグが設定され、partSize値がゼロ(0)に設定されていることがわかります。このマイナーチェンジを行うと、アップロードが成功し、その後のダウンロードも成功しました。だから、 "マジック"ソースは、isLastPartを "true"に設定するとき、最後の部分のリクエストでpartSizeをゼロに設定するように見えます。正確にはなぜこの作品は推測の問題ですが、これまで問題を解決しているようです。もう少しテストした後、サポート文書はありませんが、私は先に進んで "答え"として書きます。 – user2107846