

本文為英文版的機器翻譯版本，如內容有任何歧義或不一致之處，概以英文版為準。

# 在 Amazon S3 中檢查物件完整性
<a name="checking-object-integrity"></a>

Amazon S3 在整個物件的儲存生命週期中，提供各種資料保護功能。您可以藉由 Amazon S3 來使用檢查總和值，驗證上傳或下載的資料完整性。此外，您可以請求為儲存在 S3 中的任何物件計算另一個檢查總和值。

上傳、複製或管理資料時，您可以從數種支援的檢查總和演算法中選擇：
+ CRC-64/NVME (`CRC64NVME`)
**注意**  
`CRC64NVME` 檢查總和演算法，是用於檢查總和計算的預設檢查總和演算法。
+ CRC-32 (`CRC32`)
+ CRC-32C (`CRC32C`)
+ SHA-1 (`SHA1`)
+ SHA-256 (`SHA256`)
+ MD5 (`MD5`)
**注意**  
對於分段上傳，運算檢查總和作業會使用 `MD5` 來提供完整的物件檢查總和值，而這在上傳期間是行不通的。對於單一部分上傳，`content-MD5 header` 只能使用物件的 S3 ETag，且必須使用 SSE-S3 加密。

當您上傳物件至 S3 時，可以指定使用這些檢查總和演算法的任何部分。對於上傳，所有 AWS擁有的用戶端都會計算物件的檢查總和，並與上傳請求一起傳送。然後，S3 會單獨計算伺服器端物件的檢查總和值，並在儲存物件和檢查總和值之前，使用提供的值進行驗證。當執行單一部分上傳或分段上傳時，您也可以提供這些檢查總和演算法的預先計算值 (使用分段上傳的完整物件檢查總和類型)。若要搭配多個物件使用預先計算的值，請使用 AWS CLI 或 AWS SDKs。

或者，如果您想要在 S3 中驗證資料集，而不需還原或下載資料，您可以搭配 S3 Batch Operations 使用**運算檢查總和**作業。**運算檢查總和**作業，可讓您有效驗證一個任務請求中的數十億個物件。執行**運算檢查總和**作業時，S3 會計算靜態物件清單的檢查總和值。在任務請求結束時，您會收到自動產生的完整性報告 (也稱為完成報告)，可用來確認資料集保持不變。

**Topics**
+ [

# 在 Amazon S3 中檢查資料上傳的物件完整性
](checking-object-integrity-upload.md)
+ [

# 檢查 Amazon S3 中靜態資料的物件完整性
](checking-object-integrity-at-rest.md)

# 在 Amazon S3 中檢查資料上傳的物件完整性
<a name="checking-object-integrity-upload"></a>

Amazon S3 使用檢查總和值驗證上傳或下載作業期間的資料完整性。當您上傳資料時， AWS SDK 和 AWS 管理主控台 會使用您選擇的檢查總和演算法，在資料傳輸之前運算檢查總和值。然後，S3 會獨立計算資料的檢查總和，並根據提供的檢查總和值進行驗證。只有在確認傳輸過程中保持資料完整性後，才會接受物件。S3 會將檢查總和值同時儲存為物件中繼資料和物件本身。

要驗證物件的資料完整性，您可以在下載過程中請求檢查總和值。此驗證方法在加密模式、物件大小、儲存類別以及單一部分上傳和分段上傳過程中，均能保持一致性。若要變更上傳的檢查總和演算法，您可以複製個別物件，或使用多個物件的批次複製。

對於單一部分上傳，您可以提供檢查總和值做為標頭。您可以提供預先計算的值，或讓 AWS SDK 在上傳期間計算值。如果 S3 計算的檢查總和值符合您提供的值，則會接受請求。如果值不相符，則會拒絕請求。

對於分段上傳， AWS SDKs 可以自動為區塊上傳建立結尾檢查總和。當您使用尾部檢查總和時，Amazon S3 會使用您指定的演算法為每個部分產生檢查總和值，並將檢查總和值附加到分塊上傳請求的末尾。S3 會在單一傳遞中執行驗證與上傳作業，以提高效率。如需詳細資訊，請參閱[使用追蹤檢查總和](#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` 標頭僅可透過 S3 ETag 用於使用 SSE-S3 加密的單一部分上傳作業 (`PUT` 操作) 所上傳的物件。

此外，您還可以使用 Content-MD5 標頭來提供每個請求的檢查總和。

當您[上傳物件](https://docs.aws.amazon.com/AmazonS3/latest/userguide/upload-objects.html)時，您可以指定要使用的演算法：
+ **使用 時 AWS 管理主控台**，請選擇您要使用的檢查總和演算法。您可以選擇指定物件的檢查總和值。Amazon S3 接收物件時，它會使用您指定的演算法計算檢查總和。如果兩個檢查總和值不相符，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 Batch Operations](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 中，支援兩種檢查總和類型：
+ **完整物件檢查總和：**完整物件檢查總和是根據分段上傳的所有內容來計算，涵蓋從第一個組件第一個位元組到最後一個組件最後一個位元組的所有資料。請注意，如果您使用 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 開發套件會將檢查總和傳遞給 Amazon S3，S3 會驗證物件完整性伺服器端，並將其與接收的值進行比較。如果值相符，則 Amazon S3 會儲存物件。如果這兩個值不相符，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 都會將此複製作為單獨操作進行。使用複製命令，物件的檢查總和是完整物件的直接檢查總和。如果物件最初是使用分段上傳方式進行上傳，即使資料沒有變更，檢查總和值也會變更。
+ 超過 `CopyObject` API 操作大小上限的物件必須使用[分段複製命令](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 SDKs
<a name="CheckObjectIntegritySDK"></a>

下列範例示範如何使用 AWS SDKs 上傳包含分段上傳的大型檔案、下載大型檔案，以及驗證分段上傳檔案，全都使用 SHA-256 進行檔案驗證。

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

**Example 範例：使用 SHA-256 上傳、下載和驗證大型檔案**  
如需建立和測試工作範例的說明，請參閱《 適用於 Java 的 AWS SDK 開發人員指南》中的[入門](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>

您可以傳送 `PUT` 請求，以便在單一操作中上傳多達 5 GB 的物件。如需詳細資訊，請參閱*《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>

上傳後驗證物件完整性的另一種方法，是在上傳物件時提供物件的 MD5 摘要。如果要計算物件的 MD5 摘要，您可以使用 `Content-MD5` 標頭搭配 `PUT` 命令提供摘要。

上傳物件後，Amazon S3 會計算物件的 MD5 摘要，並將其與您提供的值進行比較。僅當兩個摘要匹配時，請求才會成功。

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-object-lambda` 而不是 `s3`。此行為會影響追蹤檢查總和值的簽名。如需 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` 適用於不使用承載簽署的請求，`STREAMING-AWS4-HMAC-SHA256-PAYLOAD-TRAILER` 適用於使用 SigV4 承載簽署的請求。(如需實作已簽署承載的詳細資訊，請參閱[授權標頭的簽章計算：在多個區塊中傳輸承載](https://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-streaming.html)。)
+ **`x-amz-trailer`：**此標頭表示請求中尾部標頭的名稱。如果存在結尾檢查總和 （其中 AWS SDKs 會將檢查總和附加到編碼的請求內文），`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 時，上傳請求會包含下列區塊類型 (依列出的順序格式化)：
+ **物件主體區塊：**可以有一個、多個或零個與分塊上傳請求相關聯的主體區塊。
+ **完成區塊：**可以有一個、多個或零個與分塊上傳請求相關聯的主體區塊。
+ **尾部區塊：**尾部檢查總和會在完成區塊之後列出。僅允許一個尾部區塊。

**注意**  
 每個分塊上傳都必須以最終 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>

物件主體區塊的開頭是物件主體區塊中位元組數的十六進位編碼，後面接著 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
```

如需區塊簽署的詳細資訊，請參閱[Authorization標頭的簽章計算：在多個區塊中傳輸承載 (AWS 簽章版本 4)](https://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-streaming.html)。如需區塊格式化的詳細資訊，請參閱 *RFC 編輯器*網站上的[區塊傳輸編碼](https://www.rfc-editor.org/rfc/rfc9112#name-chunked-transfer-coding)。

#### 完成區塊
<a name="trailing-checksums-completion-chunks"></a>

完成區塊必須是每個分塊上傳的最終物件主體區塊。完成區塊的格式，相似於主體區塊，但一律包含零位元組的物件資料。(物件資料的零位元組表示所有資料都已上傳。) 分塊上傳必須包含完成區塊做為其最終物件主體區塊，格式如下所示：

```
0\r\n
```

不過，如果內容編碼請求使用承載簽署，則會改為遵循此格式：

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

#### 尾部區塊
<a name="trailing-checksums-trailer-chunks"></a>

尾部區塊會保留所有 S3 上傳請求的計算檢查總和。尾部區塊包含兩個欄位：一個標頭名稱欄位和一個標頭值欄位。上傳請求的標頭名稱欄位必須符合傳入 `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` 和 `UploadPart` 請求採用 `aws-chunked` 內容編碼，並附加尾部檢查總和。

**Example 1 – 具有尾部 CRC-32 檢查總和的未簽署分塊 `PutObject` 請求**  

 以下是具有尾部 CRC-32 檢查總和的分塊 `PutObject` 請求範例。在此範例中，用戶端會在三個未簽署區塊中上傳 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==
```

**注意**  
 檢查總和值尾部對 linefeed `\n` 的使用，可能因用戶端而異。

**Example 2 – 具有尾部 CRC-32 (`CRC32`) 檢查總和的 SigV4 簽署的分塊 `PutObject` 請求**  

以下是具有尾部 CRC-32 檢查總和的分塊 `PutObject` 請求範例。此請求使用 SigV4 承載簽署。在此範例中，用戶端會在三個已簽署區塊中上傳 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==
```

# 檢查 Amazon S3 中靜態資料的物件完整性
<a name="checking-object-integrity-at-rest"></a>

如果您需要驗證儲存在 Amazon S3 中的資料集內容，S3 Batch Operations [運算檢查總和](https://docs.aws.amazon.com//AmazonS3/latest/userguide/batch-ops-compute-checksums.html)作業會計算靜態物件的完整物件，或複合檢查總和。**運算檢查總和**作業使用批次操作來非同步計算一組物件的檢查總和值，並自動產生合併完整性報告，無需建立新的資料複本，或還原或下載任何資料。

藉由**運算檢查總和**作業，您可以透過單一作業請求，有效率地驗證數十億個物件。對於每個**運算檢查總和**任務請求，S3 會計算檢查總和值，並將其包含在自動產生的完整性報告 (也稱為完成報告) 中。然後，您可以使用完成報告來驗證資料集的完整性。

**運算檢查總和**作業適用於儲存在 S3 中的任何物件，無論儲存類別或物件大小。無論您需要將物件驗證為資料保留最佳實務，或是滿足合規要求，**運算檢查總和**作業都會透過執行靜態檢查總和計算，降低資料驗證所需的成本、時間和付出。如需**運算檢查總和**定價的相關資訊，請參閱 [Amazon S3 定價](https://aws.amazon.com/s3/pricing/)上的**管理和洞察**索引標籤。

然後，您可以使用產生的完成報告的輸出，與您儲存在資料庫中的檢查總和值進行比較，確認您的資料集隨著時間推移仍保持不變。此方法可協助您維持端對端資料完整性，以滿足業務和合規需求。例如，您可以使用**運算檢查總和**作業提交 S3 Glacier 儲存類別中儲存物件清單，以進行年度安全稽核。此外，支援的檢查總和演算法範圍可讓您維持在應用程式中使用演算法的連續性。

## 使用支持的檢查總和演算法
<a name="using-additional-checksums-rest"></a>

對於靜態資料，您可以使用任何支援的檢查總和演算法來計算檢查總和：
+ CRC-64/NVME (`CRC64NVME`)：僅支援完整的物件檢查總和類型。
+ CRC-32 (`CRC32`)：支援完整物件與合成檢查總和類型。
+ CRC-32C (`CRC32C`)：支援完整物件與合成檢查總和類型。
+ SHA-1 (`SHA1`)：支援完整物件與合成檢查總和類型。
+ SHA-256 (`SHA256`)：支援完整物件與合成檢查總和類型。
+ MD5 (`MD5`)：支援完整物件與合成演算法類型。

## 使用**運算檢查總和**
<a name="Compute-checksums"></a>

對於儲存在 Amazon S3 中的物件，您可以搭配使用**運算檢查總和**作業和 S3 Batch Operations，檢查儲存的靜態資料內容。您可以使用 Amazon S3 主控台、 AWS Command Line Interface (AWS CLI)、REST API 或 AWS SDK [建立Compute checksum批次操作任務](https://docs.aws.amazon.com/AmazonS3/latest/userguide/batch-ops-create-job.html)。當**運算檢查總和**任務完成時，您會收到完成報告。如需有關如何使用完成報告的詳細資訊，請參閱[追蹤任務狀態和完成報告](https://docs.aws.amazon.com/AmazonS3/latest/userguide/batch-ops-job-status.html)。

在建立**運算檢查總**和任務之前，您必須建立 S3 批次操作 AWS Identity and Access Management (IAM) 角色，以授予 Amazon S3 代表您執行動作的許可。您需要授予權限來讀取資訊清單檔案，並將完成報告寫入 S3 儲存貯體。如需詳細資訊，請參閱[運算檢查總和](batch-ops-compute-checksums.md)。

### 使用 S3 主控台
<a name="Compute-checksum-console"></a>

**使用**運算檢查總和**作業**

1. 登入 AWS 管理主控台 ，並在 https：//[https://console.aws.amazon.com/s3/](https://console.aws.amazon.com/s3/) 開啟 Amazon S3 主控台。

1. 在頁面頂端的導覽列中，選擇目前顯示的名稱 AWS 區域。​接下來，選擇您要在其中建立作業的區域。
**注意**  
對於複製操作，您必須在與目的地儲存貯體相同的區域中建立作業。對於所有其他操作，您必須在與資訊清單中的物件相同的區域中建立作業。

1. 在 Amazon S3 主控台的左側導覽窗格上，選擇 **Batch Operations**。

1. 選擇**建立任務**。

1. 檢視您要建立任務 AWS 區域 的 。
**注意**  
對於複製操作，您必須在與目的地儲存貯體相同的區域中建立作業。對於所有其他操作，您必須在與資訊清單中的物件相同的區域中建立作業。

1. 在 **Manifest format** (資訊清單格式) 下，選擇要使用的資訊清單物件類型。
   + 如果您選擇 **S3 庫存報告 (manifest.json)**，請輸入 `manifest.json` 物件的路徑；如果您想要使用特定物件版本時，則可選擇**資訊清單物件版本 ID**。或者，您可以選擇**瀏覽 S3**，並選擇資訊清單 JSON 檔案，該檔案會自動填入所有資訊清單物件欄位項目。
   + 如果您選擇 **CSV**，請選擇資訊清單位置類型，然後輸入 CSV 格式資訊清單物件的路徑，或選擇**瀏覽 S3** 以選取資訊清單物件。資訊清單物件必須遵循主控台中所描述的格式。如果您想要使用資訊清單物件的特定版本，也可以指定物件版本 ID。
   + 如果您選擇**使用 S3 複寫組態建立資訊清單**，則可使用複寫組態產生物件清單，並選擇性地儲存至您選擇的目的地。使用複寫組態產生資訊清單時，唯一可用的操作是**複寫**。

1. 選擇**下一步**。

1. 在**操作**下，選擇**運算檢查總和**作業，以計算資訊清單中列出之所有物件的檢查總和。選擇您任務的**檢查總和類型**和**檢查總和函數**。然後選擇**下一步**。

1. 填寫**設定其他選項**的資訊，然後選擇**下一步**。

1. 在**設定其他選項**頁面上，填寫**運算檢查總和**任務的資訊。
**注意**  
在**完成報告**下，務必確認收到資訊。確認收到資訊表示您已了解完成報告包含檢查總和值，並且用於驗證儲存在 Amazon S3 中的資料的完整性。因此，應謹慎分享完成報告。此外，請注意，如果您要建立運算檢查總和請求，並指定外部帳戶擁有者的儲存貯體位置來存放完成報告，請務必指定外部儲存貯體擁有者的 AWS 帳戶 ID。

1. 選擇**下一步**。

1. 在**檢視**頁面上，檢視和確認您的設定。

1. (選用) 如果您需要變更，請選擇**上一步**以返回上一頁，或選擇**編輯**以更新特定步驟。

1. 確認變更後，選擇**建立任務**。

**列出和監控所有**運算檢查總和**請求的進度**

1. 登入 AWS 管理主控台 ，並在 [https://console.aws.amazon.com/s3/](https://console.aws.amazon.com/s3/)：// 開啟 Amazon S3 主控台。

1. 在左側導覽窗格中，選擇 **Batch Operations** (批次操作)。

1. 在**批次操作**頁面上，您可以檢閱任務詳細資訊，例如任務優先順序、任務完成率和物件總數。

1. 如果您想要管理或複製特定的**運算檢查總和**任務，請按一下**任務 ID** 來檢閱其他任務資訊。

1. 在特定**運算檢查總和**任務頁面上，檢閱任務詳細資訊。

每個批次操作任務都會經歷不同的[任務狀態](https://docs.aws.amazon.com/AmazonS3/latest/userguide/batch-ops-job-status.html#batch-ops-job-status-table)。您也可以在 S3 主控台[啟用 AWS CloudTrail 事件](https://docs.aws.amazon.com/AmazonS3/latest/userguide/enable-cloudtrail-logging-for-s3.html)，以在發生任何任務狀態變更時收到提醒。對於作用中任務，您可以在**任務詳細資訊**頁面上檢閱執行中的任務和完成率。

### 使用 AWS SDKs
<a name="Compute-checksum-sdk"></a>

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

**Example 範例：建立**運算檢查總和**任務**  
下列範例說明如何建立**運算檢查總和**任務 (做為**建立任務**請求的一部分)，以及如何指定資訊清單：  

```
// Required parameters
String accountId = "111122223333";
String roleArn = "arn:aws:iam::111122223333:role/BatchOperations";
String manifestArn = "arn:aws:s3:::my_manifests/manifest.csv";
String manifestEtag = "60e460c9d1046e73f7dde5043ac3ae85";
String reportBucketArn = "arn:aws:s3:::amzn-s3-demo-completion-report-bucket";
String reportExpectedBucketOwner = "111122223333";
String reportPrefix = "demo-report";

// Job Operation
S3ComputeObjectChecksumOperation s3ComputeObjectChecksum = S3ComputeObjectChecksumOperation.builder()
    .checksumAlgorithm(ComputeObjectChecksumAlgorithm.CRC64)
    .checksumType(ComputeObjectChecksumType.COMPOSITE)
    .build();

JobOperation operation = JobOperation.builder()
    .s3ComputeObjectChecksum(s3ComputeObjectChecksum)
    .build();

// Job Manifest
JobManifestLocation location = JobManifestLocation.builder()
    .eTag(manifestEtag)
    .objectArn(manifestArn)
    .build();

JobManifestSpec spec = JobManifestSpec.builder()
    .format(JobManifestFormat.S3_BATCH_OPERATIONS_CSV_20180820)
    .fields(Arrays.asList(JobManifestFieldName.BUCKET, JobManifestFieldName.KEY))
    .build();

JobManifest manifest = JobManifest.builder()
    .location(location)
    .spec(spec)
    .build();

// Completion Report
JobReport report = JobReport.builder()
    .bucket(reportBucketArn)
    .enabled(true) // Must be true
    .expectedBucketOwner(reportExpectedBucketOwner)
    .format(JobReportFormat.REPORT_CSV_20180820)
    .prefix(reportPrefix)
    .reportScope(JobReportScope.ALL_TASKS)
    .build();

// Create Job Request
CreateJobRequest request = CreateJobRequest.builder()
    .accountId(accountId)
    .confirmationRequired(false)
    .manifest(manifest)
    .operation(operation)
    .priority(10)
    .report(report)
    .roleArn(roleArn);

// Create the client
S3ControlClient client = S3ControlClient.builder()
    .credentialsProvider(new ProfileCredentialsProvider())
    .region(Region.US_EAST_1)
    .build();

// Send the request
try {
    CreateJobResponse response = client.createJob(request);
    System.out.println(response);    
} catch (AwsServiceException e) {
    System.out.println("AwsServiceException: " + e.getMessage());
    throw new RuntimeException(e);
} catch (SdkClientException e) {
    System.out.println("SdkClientException: " + e.getMessage());
    throw new RuntimeException(e);
}
```

**Example 範例：檢視**運算檢查總和**任務詳細資訊**  
下列範例說明如何指定任務 ID，以檢視**運算檢查總和**任務請求的任務詳細資訊 (例如任務完成率)：  

```
DescribeJobRequest request = DescribeJobRequest.builder()
        .accountId("1234567890")
        .jobId("a16217a1-e082-48e5-b04f-31fac3a66b13")
        .build();
```

------

### 使用 AWS CLI
<a name="Compute-checksum-cli"></a>

您可以使用 [https://docs.aws.amazon.com/cli/latest/reference/s3control/create-job.html](https://docs.aws.amazon.com/cli/latest/reference/s3control/create-job.html) 命令建立新的批次操作任務，並提供物件清單。然後，指定檢查總和演算法和檢查總和類型，以及您要儲存**運算檢查總和**報告的目的地儲存貯體。下列範例會針對 AWS 帳戶 *111122223333* 使用 S3 產生的資訊清單，建立 Batch Operations **運算檢查總和**任務。

若要使用此命令，請以您自己的資訊取代*使用者輸入預留位置*。

```
aws s3control create-job \
    --account-id 111122223333 \
    --manifest '{"Spec":{"Format":"S3BatchOperations_CSV_20180820","Fields":["Bucket","Key"]},"Location":{"ObjectArn":"arn:aws:s3:::my-manifest-bucket/manifest.csv","ETag":"e0e8bfc50e0f0c5d5a1a5f0e0e8bfc50"}}' \
    --manifest-generator '{
        "S3JobManifestGenerator": {
          "ExpectedBucketOwner": "111122223333",
          "SourceBucket": "arn:aws:s3:::amzn-s3-demo-source-bucket",
          "EnableManifestOutput": true,
          "ManifestOutputLocation": {
            "ExpectedManifestBucketOwner": "111122223333",
            "Bucket": "arn:aws:s3:::amzn-s3-demo-manifest-bucket",
            "ManifestPrefix": "prefix",
            "ManifestFormat": "S3InventoryReport_CSV_20211130"
          },
          "Filter": {
            "CreatedAfter": "2023-09-01",
            "CreatedBefore": "2023-10-01",
            "KeyNameConstraint": {
              "MatchAnyPrefix": [
                "prefix"
              ],
              "MatchAnySuffix": [
                "suffix"
              ]
            },
            "ObjectSizeGreaterThanBytes": 100,
            "ObjectSizeLessThanBytes": 200,
            "MatchAnyStorageClass": [
              "STANDARD",
              "STANDARD_IA"
            ]
          }
        }
      }' \
    --operation '{"S3ComputeObjectChecksum":{"ChecksumAlgorithm":"CRC64NVME","ChecksumType":"FULL_OBJECT"}}' \
    --report '{"Bucket":"arn:aws:s3:::my-report-bucket","Format":"Report_CSV_20180820","Enabled":true,"Prefix":"batch-op-reports/","ReportScope":"AllTasks","ExpectedBucketOwner":"111122223333"}' \
    --priority 10 \
    --role-arn arn:aws:iam::123456789012:role/S3BatchJobRole \
    --client-request-token 6e023a7e-4820-4654-8c81-7247361aeb73 \
    --description "Compute object checksums" \
    --region us-west-2
```

提交**運算檢查總和**任務後，您會收到任務 ID 做為回應，並顯示在 S3 Batch Operations 清單頁面上。Amazon S3 會處理物件清單，並計算每個物件的檢查總和。任務完成後，S3 會在指定的目的地提供合併**運算檢查總和**報告。

若要監控**運算檢查總和**任務的進度，請使用 [https://awscli.amazonaws.com/v2/documentation/api/latest/reference/s3control/describe-job.html](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/s3control/describe-job.html) 命令。此命令會檢查指定批次操作任務的狀態。若要使用此命令，請以您自己的資訊取代*使用者輸入預留位置*。

例如：

```
aws s3control describe-job --account-id 111122223333 --job-id 1234567890abcdef0
```

若要[取得](https://docs.aws.amazon.com/AmazonS3/latest/userguide/batch-ops-list-jobs.html)所有**作用中**和**完成**批次操作任務的清單，請參閱《AWS CLI 命令參考》**中的[列出任務](https://docs.aws.amazon.com/AmazonS3/latest/userguide/batch-ops-list-jobs.html)或 [list-jobs](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/s3control/list-jobs.html)。

### 使用 REST API
<a name="Compute-checksum-api"></a>

您可以使用 [CreateJob](https://docs.aws.amazon.com/AmazonS3/latest/API/API_control_CreateJob.html)，透過**運算檢查總和**傳送 REST 請求，以驗證物件完整性。您可以透過將 REST 請求傳送至 [DescribeJob](https://docs.aws.amazon.com/AmazonS3/latest/API/API_control_DescribeJob.html) API 操作，監控**運算檢查總和**請求的進度。每個批次操作任務都會執行下列狀態：
+ **新**
+ **準備**
+ **就緒**
+ **ACTIVE**
+ **暫停**
+ **已暫停**
+ **完成**
+ **取消**
+ **失敗**

API 回應會通知您目前的任務狀態。