

# Amazon S3 でデータアップロードのオブジェクトの整合性をチェックする
<a name="checking-object-integrity-upload"></a>

Amazon S3 は、チェックサム値を使用して、アップロードおよびダウンロードオペレーション中のデータの整合性を検証します。データをアップロードすると、AWS SDK と AWS マネジメントコンソールは選択したチェックサムアルゴリズムを使用して、データ転送前にチェックサム値を計算します。次に、S3 はデータのチェックサムを個別に計算し、指定されたチェックサム値と照合して検証します。オブジェクトは、転送中にデータの整合性が維持されたことを確認した後にのみ受け入れられます。S3 は、チェックサム値をオブジェクトメタデータとして保存し、オブジェクト自体も保存します。

オブジェクトのデータ整合性を検証する場合は、ダウンロード中にチェックサム値をリクエストできます。この検証は、単一パートアップロードとマルチパートアップロードの両方に対して、暗号化モード、オブジェクトサイズ、ストレージクラス間で一貫して機能します。アップロードのチェックサムアルゴリズムを変更するには、個々のオブジェクトをコピーするか、複数のオブジェクトにバッチコピーを使用します。

単一パートアップロードの場合、チェックサム値をヘッダーとして指定できます。事前に計算された値を指定するか、アップロード中に AWS SDK に計算させることができます。S3 で計算したチェックサム値と指定した値が一致すると、リクエストが受け入れられます。値が一致しない場合、リクエストは拒否されます。

マルチパートアップロードの場合、AWS SDK はチャンクアップロードの追跡チェックサムを自動的に作成できます。追跡チェックサムを使用すると、Amazon S3 は指定したアルゴリズムを使用して各パートのチェックサム値を生成し、チャンクアップロードリクエストの最後にチェックサム値を追加します。S3 は検証とアップロードを 1 回のパスで実行し、効率を向上させます。詳細については、「[追跡チェックサムの使用](#trailing-checksums)」を参照してください。

## サポートされているチェックサムアルゴリズムの使用
<a name="using-additional-checksums"></a>

Amazon S3 では、チェックサムアルゴリズムを選択して、アップロード中にチェックサム値を計算できます。その後、指定されたチェックサムアルゴリズムがオブジェクトとともに保存され、ダウンロード中にデータの整合性を検証するために使用できます。チェックサム値を計算するには、セキュアハッシュアルゴリズム (SHA) または巡回冗長検査 (CRC) チェックアルゴリズムのいずれかを選択できます。
+ CRC-64/NVME (`CRC64NVME`)
+ CRC-32 (`CRC32`)
+ CRC-32C (`CRC32C`)
+ SHA-1 (`SHA1`)
+ SHA-256 (`SHA256`)
+ MD5 (`MD5`)
**注記**  
`content-MD5` ヘッダーは、SSE-S3 暗号化を使用する単一パートアップロード (`PUT` オペレーション) でアップロードされたオブジェクトに対して、S3 ETag を使用する場合にのみ利用可能です。

さらに、Content-MD5 ヘッダーを使用して、各リクエストにチェックサムを提供できます。

[オブジェクトをアップロード](https://docs.aws.amazon.com/AmazonS3/latest/userguide/upload-objects.html)するときに、使用するアルゴリズムを指定します。
+ **AWS マネジメントコンソール を使用するときには**、使用するチェックサムアルゴリズムを選択します。オプションでオブジェクトのチェックサム値を指定できます。Amazon S3 は、オブジェクトを受信すると、指定したアルゴリズムを使用してチェックサムを計算します。2 つの値が一致しない場合、Amazon S3 はエラーを生成します。
+ **SDK を使用するときには**、以下について注意してください。
  + `ChecksumAlgorithm` パラメータを Amazon S3 で使用するアルゴリズムに設定します。事前に計算されたチェックサムが既にある場合は、チェックサム値を AWS SDK に渡すと、SDK はリクエストにその値を含めます。チェックサム値を渡さないか、チェックサムアルゴリズムを指定しない場合、SDK はチェックサム値を自動的に計算し、リクエストに含めて整合性の保護を提供します。個々のチェックサム値がチェックサムアルゴリズムの設定値と一致しない場合、Amazon S3 は `BadDigest` エラーでリクエストに失敗します。
  + アップグレードされた AWS SDK を使用している場合、SDK がチェックサムアルゴリズムを選択します。ただし、このチェックサムアルゴリズムは上書きできます。
  + チェックサムアルゴリズムを指定せず、SDK もチェックサムを計算しない場合、S3 は自動的に CRC-64/NVME (`CRC64NVME`) チェックサムアルゴリズムを選択します。
+ **REST API を使用しているときには**、`x-amz-sdk-checksum-algorithm` パラメータを使用しないでください。代わりに、アルゴリズム固有のヘッダーのいずれかを使用します (例: `x-amz-checksum-crc32`)。

Amazon S3 に既にアップロードされているオブジェクトにこれらのチェックサム値のいずれかを適用するには、オブジェクトをコピーして、既存のチェックサムアルゴリズムを使用するか、新しいチェックサムアルゴリズムを使用するかを指定します。アルゴリズムを指定しない場合、S3 は既存のアルゴリズムを使用します。ソースオブジェクトに指定されたチェックサムアルゴリズムまたはチェックサム値がない場合、Amazon S3 は CRC-64/NVME アルゴリズムを使用して送信先オブジェクトのチェックサム値を計算します。[S3 バッチオペレーション](https://docs.aws.amazon.com/AmazonS3/latest/userguide/batch-ops.html)を使用してオブジェクトをコピーするときに、チェックサムアルゴリズムを指定することもできます。

**重要**  
複合 (またはパートレベル) チェックサムの **[チェックサム]** でマルチパートアップロードを使用する場合、マルチパートアップロードのパート番号は、連続しており 1 から始まる必要があります。連続しないパート番号でマルチパートアップロードリクエストを完了しようとすると、Amazon S3 は `HTTP 500 Internal Server` エラーを生成します。

## フルオブジェクトおよび複合チェックサムタイプ
<a name="ChecksumTypes-Uploads"></a>

Amazon S3 では、次の 2 つのタイプのチェックサムがサポートされています。
+ **フルオブジェクトチェックサム:** フルオブジェクトチェックサムは、マルチパートアップロードのすべてのコンテンツに基づいて計算され、最初のパートの最初のバイトから最後のパートの最後のバイトまでのすべてのデータをカバーします。AWS マネジメントコンソールを使用して 16 MB 未満のオブジェクトをアップロードする場合、フルオブジェクトのチェックサムタイプのみがサポートされることに注意してください。
**注記**  
すべての PUT リクエストには、フルオブジェクトのチェックサムタイプが必要です。PUT リクエストを介してオブジェクトをアップロードする場合は、フルオブジェクトのチェックサムタイプを指定する必要があります。
+ **複合チェックサム:** 複合チェックサムは、マルチパートアップロードの各パートの個々のチェックサムに基づいて計算されます。このアプローチでは、すべてのデータコンテンツに基づいてチェックサムを計算する代わりに、パートレベルのチェックサム (最初の部分から最後の部分まで) を集計して、完全なオブジェクトに対する単一の複合チェックサムを生成します。マルチパートアップロードを使用してオブジェクトをアップロードする場合は、複合チェックサムタイプを指定する必要があります。
**注記**  
オブジェクトがマルチパートアップロードとしてアップロードされるとき、オブジェクトのエンティティタグ (ETag) はオブジェクト全体の MD5 ダイジェストではありません。代わりに、Amazon S3 は、アップロードされた個々のパートの MD5 ダイジェストを計算します。MD5 ダイジェストは、最終的なオブジェクトの ETag を決定するために使用されます。Amazon S3 は MD5 ダイジェストのバイトを連結し、これらの連結値の MD5 ダイジェストを計算します。ETag 作成最終ステップの間に、Amazon S3 はパートの総数を含むダッシュを末尾に追加します。

Amazon S3 は、次のフルオブジェクトおよび複合チェックサムアルゴリズムタイプをサポートしています。
+ CRC-64/NVME (`CRC64NVME`): フルオブジェクトのチェックサムタイプのみをサポートします。
+ CRC-32 (`CRC32`): フルオブジェクトおよび複合チェックサムタイプの両方をサポートします。
+ CRC-32C (`CRC32C`): フルオブジェクトおよび複合チェックサムタイプの両方をサポートします。
+ SHA-1 (`SHA1`): フルオブジェクトおよび複合チェックサムタイプの両方をサポートします。
+ SHA-256 (`SHA256`): フルオブジェクトおよび複合チェックサムタイプの両方をサポートします。
+ MD5 (`MD5`): フルオブジェクトおよび複合チェックサムタイプの両方をサポートします。

### シングルパートアップロード
<a name="SinglePartUploads-Checksums"></a>

シングルパートでアップロード ([https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutObject.html#API_PutObject](https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutObject.html#API_PutObject) を使用) されたオブジェクトのチェックサムは、フルオブジェクトチェックサムとして扱われます。Amazon S3 コンソールでオブジェクトをアップロードするときに、S3 で使用するチェックサムアルゴリズムを選択し、(オプションで) 事前に計算された値を指定することもできます。次に、Amazon S3 は、オブジェクトとそのチェックサム値を保存する前に、事前に計算されたチェックサム値を検証します。オブジェクトのダウンロード中にチェックサム値をリクエストするときに、オブジェクトのデータ整合性を検証できます。

### マルチパートアップロード
<a name="MultipartUploads-Checksums"></a>

[https://docs.aws.amazon.com/AmazonS3/latest/API/API_MultipartUpload.html](https://docs.aws.amazon.com/AmazonS3/latest/API/API_MultipartUpload.html) API を使用してオブジェクトを複数のパートに分けてアップロードする場合、Amazon S3 で使用するチェックサムアルゴリズムとチェックサムタイプ (フルオブジェクトまたは複合) を指定できます。

 次の表は、マルチパートアップロードの各チェックサムアルゴリズムでサポートされているチェックサムアルゴリズムタイプを示しています。


| チェックサムアルゴリズム | フルオブジェクト | 複合 | 
| --- | --- | --- | 
| CRC-64/NVME (CRC64NVME) | はい | なし | 
| CRC-32 (CRC32) | 可能 | はい | 
| CRC-32C (CRC32C) | 可能 | はい | 
| SHA-1 (SHA1) | いいえ | あり | 
| SHA-256 (SHA256) | いいえ | あり | 

## マルチパートアップロードへのフルオブジェクトチェックサムの使用
<a name="Full-object-checksums"></a>

マルチパートアップロードを作成または実行するときは、アップロード時の検証にフルオブジェクトチェックサムを使用できます。つまり、[https://docs.aws.amazon.com/AmazonS3/latest/API/API_MultipartUpload.html](https://docs.aws.amazon.com/AmazonS3/latest/API/API_MultipartUpload.html) API にチェックサムアルゴリズムを提供できることを意味します。アップロードされたオブジェクトのパート境界を追跡する必要がなくなるため、整合性検証ツールを簡素化できます。オブジェクト全体のチェックサムとオブジェクトサイズを [https://docs.aws.amazon.com/AmazonS3/latest/API/API_CompleteMultipartUpload.html](https://docs.aws.amazon.com/AmazonS3/latest/API/API_CompleteMultipartUpload.html) リクエストで指定できます。

マルチパートアップロード中にフルオブジェクトチェックサムを指定すると、AWS SDK はそのチェックサムを Amazon S3 に渡し、S3 はオブジェクトの整合性をサーバー側で検証して、受信した値と比較します。次に、値が一致すると、Amazon S3 はオブジェクトを保存します。2 つの値が一致しない場合、S3 は `BadDigest` エラーでリクエストに失敗します。オブジェクトのチェックサムはオブジェクトメタデータにも保存され、後でオブジェクトのデータ整合性を検証するために使用します。

フルオブジェクトチェックサムには、S3 で CRC-64/NVME (`CRC64NVME`)、CRC-32 (`CRC32`)、または CRC-32C (`CRC32C`) チェックサムアルゴリズムを使用できます。マルチパートアップロードのフルオブジェクトチェックサムは、フルオブジェクトチェックサムに線形化できるため、CRC ベースのチェックサムでのみ使用できます。この線形化により、Amazon S3 はリクエストを並列化してパフォーマンスを向上させることができます。特に、S3 はパートレベルのチェックサムからオブジェクト全体のチェックサムを計算できます。このタイプの検証は、SHA や MD5 などの他のアルゴリズムでは使用できません。S3 にはデフォルトの整合性保護があるため、チェックサムなしでオブジェクトをアップロードすると、S3 は推奨されるフルオブジェクト CRC-64/NVME (`CRC64NVME`) チェックサムアルゴリズムをオブジェクトに自動的にアタッチします。

**注記**  
マルチパートアップロードを開始するには、チェックサムアルゴリズムとフルオブジェクトチェックサムタイプを指定できます。チェックサムアルゴリズムとフルオブジェクトチェックサムタイプを指定した後、マルチパートアップロードのフルオブジェクトチェックサム値を指定できます。

## マルチパートアップロードへのパートレベルのチェックサムの使用
<a name="Part-level-checksums"></a>

オブジェクトが Amazon S3 にアップロードされるときには、単一のオブジェクトとしてアップロードされるか、マルチパートアップロードプロセスを使用してパートに分割してアップロードされます。マルチパートアップロードの **[チェックサム]** タイプを選択できます。マルチパートアップロードのパートレベルのチェックサム (または複合チェックサム) の場合、Amazon S3 は指定されたチェックサムアルゴリズムを使用して個々のパートのチェックサムを計算します。[https://docs.aws.amazon.com/AmazonS3/latest/API/API_UploadPart.html](https://docs.aws.amazon.com/AmazonS3/latest/API/API_UploadPart.html) を使用して、各パートのチェックサム値を指定できます。Amazon S3 コンソールでアップロードしようとしているオブジェクトが CRC-64/NVME (`CRC64NVME`) チェックサムアルゴリズムを使用するように設定されていて、16 MB を超える場合は、自動的にフルオブジェクトチェックサムとして指定されます。

次に、Amazon S3 は保存されたパートレベルのチェックサム値を使用して、各パートが正しくアップロードされたことを確認します。各パートのチェックサム (オブジェクト全体) を指定すると、S3 は各パートの保存されたチェックサム値を使用して、指定されたチェックサム値と比較し、フルオブジェクトチェックサムを内部的に計算します。これにより、S3 はパートのチェックサムを使用してオブジェクト全体のチェックサムを計算でき、コンピューティングコストが最小限に抑えられます。マルチパートアップロードの詳細については、「[Amazon S3 でのマルチパートアップロードを使用したオブジェクトのアップロードとコピー](mpuoverview.md)」と「[マルチパートアップロードへのフルオブジェクトチェックサムの使用](#Full-object-checksums)」を参照してください。

オブジェクトが完全にアップロードされたら、最後に計算されたチェックサムを使用して、オブジェクトのデータ整合性を検証できます。

マルチパートアップロードの一部をアップロードするときは、次の点に注意してください。
+ オブジェクト全体を構成するパートの数など、オブジェクトに関する情報を取得するには、[https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetObjectAttributes.html](https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetObjectAttributes.html) オペレーションを使用します。追加のチェックサムを使用すると、パートのチェックサム値を含む個々のパートの情報を回復することもできます。
+ 完了したアップロードでは、[https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetObject.html](https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetObject.html) または [https://docs.aws.amazon.com/AmazonS3/latest/API/API_HeadObject.html](https://docs.aws.amazon.com/AmazonS3/latest/API/API_HeadObject.html) オペレーションを使用して、シングルパートのパート番号またはバイト範囲を指定することにより、個々のパートのチェックサムを取得することもできます。マルチパートアップロード処理中の個別のパートのチェックサム値を取得する場合は、[https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListParts.html](https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListParts.html) を使用できます。
+ Amazon S3 はマルチパートオブジェクトのチェックサムを計算するので、オブジェクトをコピーした場合、チェックサム値が変更されることがあります。SDK または REST API を使用しており、[https://docs.aws.amazon.com/AmazonS3/latest/API/API_CopyObject.html](https://docs.aws.amazon.com/AmazonS3/latest/API/API_CopyObject.html) を呼び出した場合、Amazon S3 は `CopyObject` API オペレーションのサイズ制限までオブジェクトをコピーします。Amazon S3 は、オブジェクトが単一のリクエストでアップロードされたか、マルチパートアップロードの一部としてアップロードされたかにかかわらず、このコピーを単一のアクションとして実行します。copy コマンドでは、オブジェクトのチェックサムは、完全なオブジェクトの直接チェックサムです。オブジェクトが最初にマルチパートアップロードを使用してアップロードされた場合、データに変更がない場合でも、チェックサム値が変更されます。
+ `CopyObject` API オペレーションのサイズ制限よりも大きいオブジェクトは、[マルチパートアップロード copy コマンド](https://docs.aws.amazon.com/AmazonS3/latest/userguide/CopyingObjectsMPUapi.html)を使用する必要があります。
+ AWS マネジメントコンソール を使用していくつかの操作を実行するとき、オブジェクトのサイズが 16 MB より大きい場合、Amazon S3 はマルチパートアップロードを使用します。

## チェックサム方式
<a name="ChecksumMethods"></a>

オブジェクトをアップロードした後、チェックサム値を取得し、事前計算済みまたは以前に保存された同じチェックサムアルゴリズムタイプのチェックサム値と比較できます。次の例は、データの整合性を検証するために使用できるチェックサム計算方法を示しています。

### S3 コンソールの使用
<a name="CheckObjectIntegrityConsole"></a>

コンソールの使用方法およびオブジェクトのアップロード時に使用するチェックサムアルゴリズムの指定方法の詳細については、「[オブジェクトのアップロード](upload-objects.md)」および「[チュートリアル: チェックサムを追加して Amazon S3 のデータの整合性をチェックする](https://aws.amazon.com/getting-started/hands-on/amazon-s3-with-additional-checksums/?ref=docs_gateway/amazons3/checking-object-integrity.html)」を参照してください。

### AWS SDK の使用
<a name="CheckObjectIntegritySDK"></a>

次の例は、AWS SDK を使用して、マルチパートアップロードで大きなファイルをアップロードする方法、大きなファイルをダウンロードする方法、およびマルチパートアップロードファイルを検証する方法を示しています。ファイル検証にはすべて SHA-256 を使用しています。

------
#### [ Java ]

**Example 例: SHA-256 を使用して大きなファイルをアップロード、ダウンロード、および検証する**  
作業サンプルの作成およびテストの手順については、「AWS SDK for Java のデベロッパーガイド」の「[使用開始](https://docs.aws.amazon.com/sdk-for-java/v1/developer-guide/getting-started.html)」を参照してください。  

```
    import software.amazon.awssdk.auth.credentials.AwsCredentials;
    import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider;
    import software.amazon.awssdk.core.ResponseInputStream;
    import software.amazon.awssdk.core.sync.RequestBody;
    import software.amazon.awssdk.regions.Region;
    import software.amazon.awssdk.services.s3.S3Client;
    import software.amazon.awssdk.services.s3.model.AbortMultipartUploadRequest;
    import software.amazon.awssdk.services.s3.model.ChecksumAlgorithm;
    import software.amazon.awssdk.services.s3.model.ChecksumMode;
    import software.amazon.awssdk.services.s3.model.CompleteMultipartUploadRequest;
    import software.amazon.awssdk.services.s3.model.CompleteMultipartUploadResponse;
    import software.amazon.awssdk.services.s3.model.CompletedMultipartUpload;
    import software.amazon.awssdk.services.s3.model.CompletedPart;
    import software.amazon.awssdk.services.s3.model.CreateMultipartUploadRequest;
    import software.amazon.awssdk.services.s3.model.CreateMultipartUploadResponse;
    import software.amazon.awssdk.services.s3.model.GetObjectAttributesRequest;
    import software.amazon.awssdk.services.s3.model.GetObjectAttributesResponse;
    import software.amazon.awssdk.services.s3.model.GetObjectRequest;
    import software.amazon.awssdk.services.s3.model.GetObjectResponse;
    import software.amazon.awssdk.services.s3.model.GetObjectTaggingRequest;
    import software.amazon.awssdk.services.s3.model.ObjectAttributes;
    import software.amazon.awssdk.services.s3.model.PutObjectTaggingRequest;
    import software.amazon.awssdk.services.s3.model.Tag;
    import software.amazon.awssdk.services.s3.model.Tagging;
    import software.amazon.awssdk.services.s3.model.UploadPartRequest;
    import software.amazon.awssdk.services.s3.model.UploadPartResponse;
     
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.OutputStream;
    import java.nio.ByteBuffer;
    import java.security.MessageDigest;
    import java.security.NoSuchAlgorithmException;
    import java.util.ArrayList;
    import java.util.Base64;
    import java.util.List;
     
    public class LargeObjectValidation {
        private static String FILE_NAME = "sample.file";
        private static String BUCKET = "sample-bucket";
        //Optional, if you want a method of storing the full multipart object checksum in S3.
        private static String CHECKSUM_TAG_KEYNAME = "fullObjectChecksum";
        //If you have existing full-object checksums that you need to validate against, you can do the full object validation on a sequential upload.
        private static String SHA256_FILE_BYTES = "htCM5g7ZNdoSw8bN/mkgiAhXt5MFoVowVg+LE9aIQmI=";
        //Example Chunk Size - this must be greater than or equal to 5MB.
        private static int CHUNK_SIZE = 5 * 1024 * 1024;
     
        public static void main(String[] args) {
            S3Client s3Client = S3Client.builder()
                    .region(Region.US_EAST_1)
                    .credentialsProvider(new AwsCredentialsProvider() {
                        @Override
                        public AwsCredentials resolveCredentials() {
                            return new AwsCredentials() {
                                @Override
                                public String accessKeyId() {
                                    return Constants.ACCESS_KEY;
                                }
     
                                @Override
                                public String secretAccessKey() {
                                    return Constants.SECRET;
                                }
                            };
                        }
                    })
                    .build();
            uploadLargeFileBracketedByChecksum(s3Client);
            downloadLargeFileBracketedByChecksum(s3Client);
            validateExistingFileAgainstS3Checksum(s3Client);
        }
     
        public static void uploadLargeFileBracketedByChecksum(S3Client s3Client) {
            System.out.println("Starting uploading file validation");
            File file = new File(FILE_NAME);
            try (InputStream in = new FileInputStream(file)) {
                MessageDigest sha256 = MessageDigest.getInstance("SHA-256");
                CreateMultipartUploadRequest createMultipartUploadRequest = CreateMultipartUploadRequest.builder()
                        .bucket(BUCKET)
                        .key(FILE_NAME)
                        .checksumAlgorithm(ChecksumAlgorithm.SHA256)
                        .build();
                CreateMultipartUploadResponse createdUpload = s3Client.createMultipartUpload(createMultipartUploadRequest);
                List<CompletedPart> completedParts = new ArrayList<CompletedPart>();
                int partNumber = 1;
                byte[] buffer = new byte[CHUNK_SIZE];
                int read = in.read(buffer);
                while (read != -1) {
                    UploadPartRequest uploadPartRequest = UploadPartRequest.builder()
                            .partNumber(partNumber).uploadId(createdUpload.uploadId()).key(FILE_NAME).bucket(BUCKET).checksumAlgorithm(ChecksumAlgorithm.SHA256).build();
                    UploadPartResponse uploadedPart = s3Client.uploadPart(uploadPartRequest, RequestBody.fromByteBuffer(ByteBuffer.wrap(buffer, 0, read)));
                    CompletedPart part = CompletedPart.builder().partNumber(partNumber).checksumSHA256(uploadedPart.checksumSHA256()).eTag(uploadedPart.eTag()).build();
                    completedParts.add(part);
                    sha256.update(buffer, 0, read);
                    read = in.read(buffer);
                    partNumber++;
                }
                String fullObjectChecksum = Base64.getEncoder().encodeToString(sha256.digest());
                if (!fullObjectChecksum.equals(SHA256_FILE_BYTES)) {
                    //Because the SHA256 is uploaded after the part is uploaded; the upload is bracketed and the full object can be fully validated.
                    s3Client.abortMultipartUpload(AbortMultipartUploadRequest.builder().bucket(BUCKET).key(FILE_NAME).uploadId(createdUpload.uploadId()).build());
                    throw new IOException("Byte mismatch between stored checksum and upload, do not proceed with upload and cleanup");
                }
                CompletedMultipartUpload completedMultipartUpload = CompletedMultipartUpload.builder().parts(completedParts).build();
                CompleteMultipartUploadResponse completedUploadResponse = s3Client.completeMultipartUpload(
                        CompleteMultipartUploadRequest.builder().bucket(BUCKET).key(FILE_NAME).uploadId(createdUpload.uploadId()).multipartUpload(completedMultipartUpload).build());
                Tag checksumTag = Tag.builder().key(CHECKSUM_TAG_KEYNAME).value(fullObjectChecksum).build();
                //Optionally, if you need the full object checksum stored with the file; you could add it as a tag after completion.
                s3Client.putObjectTagging(PutObjectTaggingRequest.builder().bucket(BUCKET).key(FILE_NAME).tagging(Tagging.builder().tagSet(checksumTag).build()).build());
            } catch (IOException | NoSuchAlgorithmException e) {
                e.printStackTrace();
            }
            GetObjectAttributesResponse
                    objectAttributes = s3Client.getObjectAttributes(GetObjectAttributesRequest.builder().bucket(BUCKET).key(FILE_NAME)
                    .objectAttributes(ObjectAttributes.OBJECT_PARTS, ObjectAttributes.CHECKSUM).build());
            System.out.println(objectAttributes.objectParts().parts());
            System.out.println(objectAttributes.checksum().checksumSHA256());
        }
     
        public static void downloadLargeFileBracketedByChecksum(S3Client s3Client) {
            System.out.println("Starting downloading file validation");
            File file = new File("DOWNLOADED_" + FILE_NAME);
            try (OutputStream out = new FileOutputStream(file)) {
                GetObjectAttributesResponse
                        objectAttributes = s3Client.getObjectAttributes(GetObjectAttributesRequest.builder().bucket(BUCKET).key(FILE_NAME)
                        .objectAttributes(ObjectAttributes.OBJECT_PARTS, ObjectAttributes.CHECKSUM).build());
                //Optionally if you need the full object checksum, you can grab a tag you added on the upload
                List<Tag> objectTags = s3Client.getObjectTagging(GetObjectTaggingRequest.builder().bucket(BUCKET).key(FILE_NAME).build()).tagSet();
                String fullObjectChecksum = null;
                for (Tag objectTag : objectTags) {
                    if (objectTag.key().equals(CHECKSUM_TAG_KEYNAME)) {
                        fullObjectChecksum = objectTag.value();
                        break;
                    }
                }
                MessageDigest sha256FullObject = MessageDigest.getInstance("SHA-256");
                MessageDigest sha256ChecksumOfChecksums = MessageDigest.getInstance("SHA-256");
     
                //If you retrieve the object in parts, and set the ChecksumMode to enabled, the SDK will automatically validate the part checksum
                for (int partNumber = 1; partNumber <= objectAttributes.objectParts().totalPartsCount(); partNumber++) {
                    MessageDigest sha256Part = MessageDigest.getInstance("SHA-256");
                    ResponseInputStream<GetObjectResponse> response = s3Client.getObject(GetObjectRequest.builder().bucket(BUCKET).key(FILE_NAME).partNumber(partNumber).checksumMode(ChecksumMode.ENABLED).build());
                    GetObjectResponse getObjectResponse = response.response();
                    byte[] buffer = new byte[CHUNK_SIZE];
                    int read = response.read(buffer);
                    while (read != -1) {
                        out.write(buffer, 0, read);
                        sha256FullObject.update(buffer, 0, read);
                        sha256Part.update(buffer, 0, read);
                        read = response.read(buffer);
                    }
                    byte[] sha256PartBytes = sha256Part.digest();
                    sha256ChecksumOfChecksums.update(sha256PartBytes);
                    //Optionally, you can do an additional manual validation again the part checksum if needed in addition to the SDK check
                    String base64PartChecksum = Base64.getEncoder().encodeToString(sha256PartBytes);
                    String base64PartChecksumFromObjectAttributes = objectAttributes.objectParts().parts().get(partNumber - 1).checksumSHA256();
                    if (!base64PartChecksum.equals(getObjectResponse.checksumSHA256()) || !base64PartChecksum.equals(base64PartChecksumFromObjectAttributes)) {
                        throw new IOException("Part checksum didn't match for the part");
                    }
                    System.out.println(partNumber + " " + base64PartChecksum);
                }
                //Before finalizing, do the final checksum validation.
                String base64FullObject = Base64.getEncoder().encodeToString(sha256FullObject.digest());
                String base64ChecksumOfChecksums = Base64.getEncoder().encodeToString(sha256ChecksumOfChecksums.digest());
                if (fullObjectChecksum != null && !fullObjectChecksum.equals(base64FullObject)) {
                    throw new IOException("Failed checksum validation for full object");
                }
                System.out.println(fullObjectChecksum);
                String base64ChecksumOfChecksumFromAttributes = objectAttributes.checksum().checksumSHA256();
                if (base64ChecksumOfChecksumFromAttributes != null && !base64ChecksumOfChecksums.equals(base64ChecksumOfChecksumFromAttributes)) {
                    throw new IOException("Failed checksum validation for full object checksum of checksums");
                }
                System.out.println(base64ChecksumOfChecksumFromAttributes);
                out.flush();
            } catch (IOException | NoSuchAlgorithmException e) {
                //Cleanup bad file
                file.delete();
                e.printStackTrace();
            }
        }
     
        public static void validateExistingFileAgainstS3Checksum(S3Client s3Client) {
            System.out.println("Starting existing file validation");
            File file = new File("DOWNLOADED_" + FILE_NAME);
            GetObjectAttributesResponse
                    objectAttributes = s3Client.getObjectAttributes(GetObjectAttributesRequest.builder().bucket(BUCKET).key(FILE_NAME)
                    .objectAttributes(ObjectAttributes.OBJECT_PARTS, ObjectAttributes.CHECKSUM).build());
            try (InputStream in = new FileInputStream(file)) {
                MessageDigest sha256ChecksumOfChecksums = MessageDigest.getInstance("SHA-256");
                MessageDigest sha256Part = MessageDigest.getInstance("SHA-256");
                byte[] buffer = new byte[CHUNK_SIZE];
                int currentPart = 0;
                int partBreak = objectAttributes.objectParts().parts().get(currentPart).size();
                int totalRead = 0;
                int read = in.read(buffer);
                while (read != -1) {
                    totalRead += read;
                    if (totalRead >= partBreak) {
                        int difference = totalRead - partBreak;
                        byte[] partChecksum;
                        if (totalRead != partBreak) {
                            sha256Part.update(buffer, 0, read - difference);
                            partChecksum = sha256Part.digest();
                            sha256ChecksumOfChecksums.update(partChecksum);
                            sha256Part.reset();
                            sha256Part.update(buffer, read - difference, difference);
                        } else {
                            sha256Part.update(buffer, 0, read);
                            partChecksum = sha256Part.digest();
                            sha256ChecksumOfChecksums.update(partChecksum);
                            sha256Part.reset();
                        }
                        String base64PartChecksum = Base64.getEncoder().encodeToString(partChecksum);
                        if (!base64PartChecksum.equals(objectAttributes.objectParts().parts().get(currentPart).checksumSHA256())) {
                            throw new IOException("Part checksum didn't match S3");
                        }
                        currentPart++;
                        System.out.println(currentPart + " " + base64PartChecksum);
                        if (currentPart < objectAttributes.objectParts().totalPartsCount()) {
                            partBreak += objectAttributes.objectParts().parts().get(currentPart - 1).size();
                        }
                    } else {
                        sha256Part.update(buffer, 0, read);
                    }
                    read = in.read(buffer);
                }
                if (currentPart != objectAttributes.objectParts().totalPartsCount()) {
                    currentPart++;
                    byte[] partChecksum = sha256Part.digest();
                    sha256ChecksumOfChecksums.update(partChecksum);
                    String base64PartChecksum = Base64.getEncoder().encodeToString(partChecksum);
                    System.out.println(currentPart + " " + base64PartChecksum);
                }
     
                String base64CalculatedChecksumOfChecksums = Base64.getEncoder().encodeToString(sha256ChecksumOfChecksums.digest());
                System.out.println(base64CalculatedChecksumOfChecksums);
                System.out.println(objectAttributes.checksum().checksumSHA256());
                if (!base64CalculatedChecksumOfChecksums.equals(objectAttributes.checksum().checksumSHA256())) {
                    throw new IOException("Full object checksum of checksums don't match S3");
                }
     
            } catch (IOException | NoSuchAlgorithmException e) {
                e.printStackTrace();
            }
        }
    }
```

------

### REST API の使用
<a name="CheckObjectIntegrityREST"></a>

REST リクエストを送信して、チェックサムの値を持つオブジェクトをアップロードし、[PutObject](https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutObject.html) でデータの整合性を検証できます。[GetObject](https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetObject.html) または [HeadObject](https://docs.aws.amazon.com/AmazonS3/latest/API/API_HeadObject.html) を使用して、オブジェクトのチェックサムの値を取得することもできます。

### AWS CLI の使用
<a name="CheckObjectIntegrityCLI"></a>

単一のオペレーションで、最大 5 GB のオブジェクトをアップロードする `PUT` リクエストを送信できます。詳細については、「*AWS CLI コマンドリファレンス*」の [https://docs.aws.amazon.com/cli/latest/reference/s3api/put-object.html#examples](https://docs.aws.amazon.com/cli/latest/reference/s3api/put-object.html#examples) を参照してください。また、[https://docs.aws.amazon.com/cli/latest/reference/s3api/get-object.html](https://docs.aws.amazon.com/cli/latest/reference/s3api/get-object.html) と [https://docs.aws.amazon.com/cli/latest/reference/s3api/head-object.html](https://docs.aws.amazon.com/cli/latest/reference/s3api/head-object.html) を使用して、すでにアップロードされたオブジェクトのチェックサムを取得し、データの整合性を検証することもできます。

詳細については、「AWS Command Line Interface ユーザーガイド」の「[Amazon S3 CLI のよくある質問](https://docs.aws.amazon.com/cli/latest/topic/s3-faq.html)」を参照してください。**

## オブジェクトをアップロードするときに Content-MD5 を使用する
<a name="checking-object-integrity-md5"></a>

アップロード後にオブジェクトの整合性を検証するもう 1 つの方法は、アップロード時にオブジェクトの MD5 ダイジェストを指定することです。オブジェクトの MD5 ダイジェストを計算した場合、`Content-MD5` ヘッダーを使用することで、`PUT` コマンドでダイジェストを指定できます。

オブジェクトをアップロードした後、Amazon S3 はオブジェクトの MD5 ダイジェストを計算し、指定した値と比較します。リクエストは、2 つのダイジェストが一致した場合にのみ成功します。

MD5 ダイジェストを指定する必要はありませんが、アップロードプロセスの一環としてオブジェクトの整合性を検証するために使用できます。

## Content-MD5 と ETag を使用して、アップロードされたオブジェクトを検証する
<a name="checking-object-integrity-etag-and-md5"></a>

オブジェクトのエンティティタグ (ETag) は、そのオブジェクトの特定のバージョンを表します。ETag は、オブジェクトのコンテンツに加えられた変更のみを反映し、メタデータに加えられた変更は反映しないことに注意してください。オブジェクトのメタデータのみが変更された場合、ETag は同じままです。

オブジェクトによっては、オブジェクトの ETag がオブジェクトデータの MD5 ダイジェストである場合があります。
+ オブジェクトが `PutObject`、`PostObject`、または `CopyObject` オペレーションによって、または AWS マネジメントコンソール を介して作成され、そのオブジェクトがプレーンテキストか、Amazon S3 マネージドキーを使用したサーバー側の暗号化 (SSE-S3) によって暗号化されている場合、そのオブジェクトの ETag は、オブジェクトデータの MD5 ダイジェストです。
+ オブジェクトが `PutObject`、`PostObject`、または `CopyObject` オペレーションによって、または AWS マネジメントコンソール を介して作成され、そのオブジェクトがお客様が用意したキーを使用したサーバー側の暗号化 (SSE-C) または AWS Key Management Service (AWS KMS) キーを使用したサーバー側の暗号化 (SSE-KMS) によって暗号化されている場合、そのオブジェクトの ETag は、オブジェクトデータの MD5 ダイジェストではありません。
+ オブジェクトがマルチパートアップロードのプロセスまたは `UploadPartCopy` オペレーションによって作成された場合、暗号化の方法に関係なく、オブジェクトの ETag は MD5 ダイジェストではありません。オブジェクトが 16 MB より大きい場合、AWS マネジメントコンソール はそのオブジェクトをマルチパートアップロードとしてアップロードまたはコピーするため、ETag は MD5 ダイジェストではありません。

ETag がオブジェクトの `Content-MD5` ダイジェストであるオブジェクトの場合、オブジェクトの ETag 値を計算済みまたは以前に保存した `Content-MD5` ダイジェストと比較できます。

## 追跡チェックサムの使用
<a name="trailing-checksums"></a>

Amazon S3 にラージオブジェクトをアップロードするときには、オブジェクトの事前計算されたチェックサムを指定するか、AWS SDK を使用して、チャンクアップロード用の追跡チェックサムを自動的に作成できます。追跡チェックサムを使用する場合、Amazon S3 は指定したアルゴリズムを使用してチェックサム値を自動的に生成し、オブジェクトのアップロード時に、チャンクアップロードでオブジェクトの整合性を検証します。

AWS SDK を使用しているときに追跡チェックサムを作成するには、`ChecksumAlgorithm` パラメータに任意のアルゴリズムを指定します。SDK は、そのアルゴリズムを使用してオブジェクト (またはオブジェクトパート) のチェックサム値を計算し、チャンクアップロードリクエストの最後に自動的に追加します。この動作により、Amazon S3 はデータの検証とアップロードを単一のパスで実行するため、時間を節約できます。

**重要**  
S3 オブジェクト Lambda を使用している場合、S3 オブジェクト Lambda へのすべてのリクエストは、`s3` の代わりに `s3-object-lambda` を使用して署名されます。この動作は、追跡チェックサム値のシグネチャに影響します。S3 Object Lambda, の詳細については、「[S3 Object Lambda を使用したオブジェクトの変換](transforming-objects.md)」を参照してください。

### 末尾のチェックサムヘッダー
<a name="trailing-checksums-headers"></a>

チャンクコンテンツエンコードのリクエストを行うために、Amazon S3 では、リクエストを正しく解析するためにクライアントサーバーに複数のヘッダーを含める必要があります。クライアントサーバーには、次のヘッダーを含める必要があります。
+ ** `x-amz-decoded-content-length`:**このヘッダーは、リクエストとともに Amazon S3 にアップロードされる実際のデータのプレーンテキストサイズを示します。
+ **`x-amz-content-sha256`:** このヘッダーは、リクエストに含まれるチャンクアップロードのタイプを示します。チェックサムが末尾にあるチャンクアップロードの場合、ヘッダー値は、ペイロード署名を使用しないリクエストの場合は `STREAMING-UNSIGNED-PAYLOAD-TRAILER`、SigV4 ペイロード署名を使用するリクエストの場合は `STREAMING-AWS4-HMAC-SHA256-PAYLOAD-TRAILER` です。(署名付きペイロードの実装の詳細については、「[Signature calculations for the authorization header: Transferring a payload in multiple chunks](https://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-streaming.html)」を参照してください。)
+ **`x-amz-trailer`:** このヘッダーは、リクエストの末尾のヘッダーの名前を示します。末尾のチェックサムが存在する場合 (AWS SDK がエンコードされたリクエスト本文にチェックサムを追加する場合)、`x-amz-trailer` ヘッダー値には `x-amz-checksum-` プレフィックスが含まれ、アルゴリズム名で終わります。現在、次の `x-amz-trailer` 値がサポートされています。
  + `x-amz-checksum-crc32`
  + `x-amz-checksum-crc32c`
  + `x-amz-checksum-crc64nvme`
  + `x-amz-checksum-sha1`
  + `x-amz-checksum-sha256`

**注記**  
リクエストには、チャンク化された値を含む `Content-Encoding` ヘッダーを含めることもできます。このヘッダーは必須ではありませんが、このヘッダーを含めることで、エンコードされたデータを送信する際の HTTP プロキシの問題を最小限に抑えることができます。リクエストに別の `Content-Encoding` ヘッダー (gzip など) が存在する場合、`Content-Encoding` ヘッダーには、エンコードのカンマ区切りリストにチャンク化された値が含まれます。例えば、`Content-Encoding: aws-chunked, gzip`。

### チャンクパーツ
<a name="trailing-checksums-chunks"></a>

チャンクエンコードを使用して Amazon S3 にオブジェクトをアップロードする場合、アップロードリクエストには次のタイプのチャンク (リストされた順序でフォーマット) が含まれます。
+ **オブジェクト本体のチャンク:** チャンクアップロードリクエストに関連付けられた本体チャンクは、1 つ、複数、またはゼロの場合があります。
+ **完了チャンク:** チャンクアップロードリクエストに関連付けられた本体チャンクは、1 つ、複数、またはゼロの場合があります。
+ **末尾チャンク:** 末尾のチェックサムは、完了チャンクの後に表示されます。末尾のチャンクは 1 つだけ許可されます。

**注記**  
 チャンクアップロードはすべて、リクエストの終了を示すために、最後の CRLF (`\r\n` など) で終わる必要があります。

チャンク形式の例については、「[例: 末尾にチェックサムが付いたチャンクアップロード](#example-chunked-uploads-trailing)」を参照してください。

#### オブジェクト本体のチャンク
<a name="trailing-checksums-object-body-chunks"></a>

オブジェクト本体のチャンクは、S3 にアップロードされる実際のオブジェクトデータを含むチャンクです。これらのチャンクには、一貫したサイズと形式の制約があります。

##### オブジェクト本体のチャンクサイズ
<a name="trailing-checksums-object-body-chunks-size"></a>

これらのチャンクには、少なくとも 8,192 バイト (または 8 KiB) のオブジェクトデータが含まれている必要があります。ただし、最後の本体チャンクは小さい場合があります。明示的な最大チャンクサイズはありませんが、すべてのチャンクが 5 GB の最大アップロードサイズより小さくなることが予想されます。チャンクサイズは、クライアントサーバーの実装に応じてチャンクごとに異なる場合があります。

##### オブジェクト本体のチャンク形式
<a name="trailing-checksums-object-body-chunks-format"></a>

オブジェクト本体のチャンクは、オブジェクト本体チャンク内のバイト数の 16 進エンコードで始まり、CRLF (キャリッジリターンラインフィード)、そのチャンクのオブジェクトバイト、および別の CRLF が続きます。

例えば、次のようになります。

```
hex-encoding-of-object-bytes-in-chunk\r\n
chunk-object-bytes\r\n
```

ただし、チャンクが署名されている場合、オブジェクト本体のチャンクは別の形式に従います。この形式では、署名がセミコロン区切り文字でチャンクサイズに追加されます。例えば、次のようになります。

```
hex-encoding-of-object-bytes-in-chunk;chunk-signature\r\n
 chunk-object-bytes\r\n
```

チャンク署名の詳細については、「[Signature calculations for the Authorization Header: Transferring a payload in multiple chunks (AWS Signature Version 4)](https://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-streaming.html)」を参照してください。チャンクの形式の詳細については、*RFC Editor* ウェブサイトの「[Chunked transfer encoding](https://www.rfc-editor.org/rfc/rfc9112#name-chunked-transfer-coding)」を参照してください。

#### 完了チャンク
<a name="trailing-checksums-completion-chunks"></a>

完了チャンクは、すべてのチャンクアップロードの最後のオブジェクト本体チャンクである必要があります。完了チャンクの形式は本体チャンクに似ていますが、常に 0 バイトのオブジェクトデータが含まれています。(オブジェクトデータの 0 バイトは、すべてのデータがアップロードされたことを示します。) チャンクアップロードには、次のような形式に従って、最後のオブジェクト本体チャンクとして完了チャンクを含める必要があります。

```
0\r\n
```

ただし、コンテンツエンコードリクエストでペイロード署名が使用されている場合、代わりに次の形式に従います。

```
0;chunk-signature\r\n
```

#### トレーラーチャンク
<a name="trailing-checksums-trailer-chunks"></a>

トレーラーチャンクは、すべての S3 アップロードリクエストの計算されたチェックサムを保持します。トレーラーチャンクには、ヘッダー名フィールド 1 つとヘッダー値フィールド 1 つの 2 つのフィールドが含まれます。アップロードリクエストのヘッダー名フィールドは、`x-amz-trailer` リクエストヘッダーに渡された値と一致する必要があります。例えば、リクエストに `x-amz-trailer: x-amz-checksum-crc32` が含まれており、トレーラーチャンクにヘッダー名 `x-amz-checksum-sha1` がある場合、リクエストは失敗します。トレーラーチャンクの値フィールドには、そのオブジェクトのビッグエンディアンチェックサム値の base64 エンコードが含まれます。(ビッグエンディアンの順序では、最上位バイトのデータが最小のメモリアドレスに、最下位バイトが最大メモリアドレスに保存されます)。このチェックサムの計算に使用されるアルゴリズムは、ヘッダー名のサフィックス (例: `crc32`) と同じです。

##### トレーラーチャンク形式
<a name="trailing-checksums-trailer-chunk-format"></a>

トレーラーチャンクは、署名なしペイロードリクエストに次の形式を使用します。

```
x-amz-checksum-lowercase-checksum-algorithm-name:base64-checksum-value\n\r\n\r\n
```

[SigV4 署名付きペイロード](https://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-streaming-trailers.html)を使用したリクエストの場合、トレーラーチャンクには、トレーラーチャンクの後にトレーラー署名が含まれます。

```
trailer-checksum\n\r\n
trailer-signature\r\n
```

また、CRLF を base64 チェックサム値の末尾に直接追加することもできます。例えば、次のようになります。

```
x-amz-checksum-lowercase-checksum-algorithm-name:base64-checksum-value\r\n\r\n
```

#### 例: 末尾にチェックサムが付いたチャンクアップロード
<a name="example-chunked-uploads-trailing"></a>

Amazon S3 は、`PutObject` に `aws-chunked` コンテンツエンコードを使用するチャンクアップロードと、末尾のチェックサムを含む `UploadPart` リクエストをサポートします。

**Example 1 – 末尾に CRC-32 チェックサムが付いた署名なしチャンク `PutObject` リクエスト**  

 以下は、末尾に CRC-32 チェックサムが付いたチャンク `PutObject` リクエストの例です。この例では、クライアントは 3 つの署名なしチャンクに 17 KB のオブジェクトをアップロードし、`x-amz-checksum-crc32` ヘッダーを使用して末尾に CRC-32 チェックサムチャンクを追加します。

```
PUT /Key+ HTTP/1.1
Host: amzn-s3-demo-bucket
Content-Encoding: aws-chunked
x-amz-decoded-content-length: 17408
x-amz-content-sha256: STREAMING-UNSIGNED-PAYLOAD-TRAILER
x-amz-trailer: x-amz-checksum-crc32

2000\r\n                                   // Object body chunk 1 (8192 bytes)
object-bytes\r\n
2000\r\n                                   // Object body chunk 2 (8192 bytes)
object-bytes\r\n
400\r\n                                    // Object body chunk 3 (1024 bytes)
object-bytes\r\n
0\r\n                                      // Completion chunk
x-amz-checksum-crc32:YABb/g==\n\r\n\r\n    // Trailer chunk (note optional \n character)
\r\n                                         // CRLF
```

レスポンスの例を次に示します。

```
HTTP/1.1 200
ETag: ETag
x-amz-checksum-crc32: YABb/g==
```

**注記**  
 チェックサム値の最後にあるラインフィード `\n` の使用は、クライアントによって異なる場合があります。

**Example 2 – 末尾に CRC-32 (`CRC32`) チェックサムが付いた SigV4 署名付きチャンク `PutObject` リクエスト**  

以下は、末尾に CRC-32 チェックサムが付いたチャンク `PutObject` リクエストの例です。このリクエストは SigV4 ペイロード署名を使用します。この例では、クライアントは 3 つの署名付きチャンクに 17 KB のオブジェクトをアップロードします。`object body` チャンクに加えて、`completion chunk` と `trailer chunk` も署名されています。

```
PUT /Key+ HTTP/1.1
Host: amzn-s3-demo-bucket.s3.amazonaws.com
Content-Encoding: aws-chunked
x-amz-decoded-content-length: 17408
x-amz-content-sha256: STREAMING-AWS4-HMAC-SHA256-PAYLOAD-TRAILER
x-amz-trailer: x-amz-checksum-crc32
		
authorization-code                            // SigV4 headers authorization

2000;chunk-signature=signature-value...\r\n   // Object body chunk 1 (8192 bytes)
object-bytes\r\n
2000;chunk-signature\r\n                      // Object body chunk 2 (8192 bytes)
object-bytes\r\n
400;chunk-signature\r\n                       // Object body chunk 3 (1024 bytes)
object-bytes\r\n
0;chunk-signature\r\n                         // Completion chunk
x-amz-checksum-crc32:YABb/g==\n\r\n            // Trailer chunk (note optional \n character)
trailer-signature\r\n
\r\n                                           // CRLF
```

レスポンスの例を次に示します。

```
HTTP/1.1 200
ETag: ETag
x-amz-checksum-crc32: YABb/g==
```