2016-10-13 5 views
3

次のコードは、マルチパート転送、クライアント側エンベロープ暗号化、および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(); 
    } 

ご迷惑をおかけして申し訳ございませんが、ご了承ください。

答えて

1

はるかにテストおよびマジック秘密ここでNETのソースコードのAWS SDKにGitのハブに洞窟探検少しコードの後に​​ゼロにUploadPartRequestPartSize設定部材(0)を設定IsLastPartメンバーを真に。

なぜこの作品が正しいのかは、いくつかの議論の問題です。最後の部分のデータは、通常暗号ブロックの境界を満たすために暗号エンジンによって埋め込まれるので、実際のContent-Lengthは暗号化が完了するまで不明である。おそらくPartSizeを0に設定すると、Content-Lengthには、で与えられた値ではなく、暗号テキストのパディングされた長さにPartSizeを設定することができます。IsLastPartがtrueに設定されているときにこれが自動的に行われないのはなぜかというと謎です。

いずれにしても、次の要約が役立ちます。クライアント側の暗号化と複数パートアップロードを使用する場合は、オブジェクトのデータの最後の部分をアップロードするときにPartSizeメンバをゼロ(0)に設定し、IsLastPartをtrueに設定します。

このコードは役に立ちます。

 while (bytesRemaining > 0) 
     { 
      long transferSize = bytesRemaining > partSize ? partSize : bytesRemaining; 
      long partIndex = fileLength - bytesRemaining; 

      bytesRemaining -= transferSize; 
      bool isLastPart = bytesRemaining == 0; 

      partNumber++; 

      UploadPartResponse resp = 
       cryptoClient.UploadPart(
        new UploadPartRequest() 
        { 
         BucketName = bucketName, 
         Key   = keyName, 
         FilePath  = uploadSourcePath, 
         FilePosition = partIndex, 
         PartSize  = isLastPart ? 0 : transferSize, 
         PartNumber = partNumber, 
         UploadId  = uploadId, 
         IsLastPart = isLastPart 
        }); 

      partETags.Add(new PartETag(partNumber, resp.ETag)); 
     } 

これが他の人に役立つことを願っています。

0

リンク先のポストに実装していただきありがとうございます。

これを明示的にサポートするために何かを読んだわけではありませんが、Amazon S3暗号化クライアントはマルチパートアップロードと互換性がない可能性があります。最終的なものではありませんが、Amazon S3暗号化クライアントとマルチパートアップロードの両方を使用したJavaの例(SDKにはKMS実装があります)を見つけることができませんでした。私が疑問を持っている理由は、ファイルが連鎖ブロックを使用して暗号化されていることです。マルチパートアップロードの各部分が断片的に暗号化されていると、連鎖ブロックが壊れ、各部分の個別初期ベクトルが失われます。

私が知る唯一の方法は、まずJavaでテストすることです。

+0

こんにちはAlton、私はあなたの実装に非常に感謝し、あなたが記述したとおりに正確に動作します。よくやった。ブロックチェーニングについては間違いなく、git hub上の.NET Transfer Utilityのソースコードを掘り下げた後、暗号化を使用しているときに複数パートの「並行」アップロードを明示的に防ぐことができます。 – user2107846

+1

そのソースをさらに調べると、複数パートアップロードの最後のブロックでisLastPartフラグが設定され、partSize値がゼロ(0)に設定されていることがわかります。このマイナーチェンジを行うと、アップロードが成功し、その後のダウンロードも成功しました。だから、 "マジック"ソースは、isLastPartを "true"に設定するとき、最後の部分のリクエストでpartSizeをゼロに設定するように見えます。正確にはなぜこの作品は推測の問題ですが、これまで問題を解決しているようです。もう少しテストした後、サポート文書はありませんが、私は先に進んで "答え"として書きます。 – user2107846

関連する問題