使用客戶提供金鑰 (SSC-C) 指定伺服器端加密 - Amazon Simple Storage Service

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

使用客戶提供金鑰 (SSC-C) 指定伺服器端加密

若要搭配客戶提供的金鑰 (SSE-C) 使用伺服器端加密,請先確定 SSE-C 不是 Amazon S3 一般用途儲存貯體的預設加密組態中的封鎖加密類型。如果封鎖,您可以透過更新儲存貯體的預設加密組態來啟用此加密類型。然後,您可以透過傳遞所需的標頭,在上傳請求中使用 SSE-C。請參閱 支援使用 SSE-C 寫入資料的 Amazon S3 動作,並確定包含 SSE-C 物件加密和解密請求所需的 S3 API 標頭

當您上傳指定 SSE-C 的物件時,Amazon S3 會使用您提供的加密金鑰,將 AES-256 加密套用至您的資料。然後,Amazon S3 會從記憶體中移除加密金鑰。當您擷取物件時,您必須在要求中提供相同的加密金鑰。Amazon S3 會先驗證您提供的加密金鑰是否相符,然後對物件進行解密,再將物件資料傳回給您。

使用 SSE-C 之前,請確定您已檢閱 使用 SSE-C 之前的考量事項

注意

Amazon S3 不會存放您提供的加密金鑰。相反地,它會存放加密金鑰的隨機雜湊訊息驗證碼 (HMAC) Salt 值,以驗證未來的請求。HMAC Salt 值不可用來衍生加密金鑰的值,或用來對加密物件的內容進行解密。換句話說,如果您遺失加密金鑰,則會遺失物件。

SSE-C 動作和必要標頭

在支援的 S3 APIs 上指定 SSE-C 需要傳遞特定請求參數。

注意

Amazon S3 中的 PutBucketEncryption API 用於設定儲存貯體的預設伺服器端加密。不過, PutBucketEncryption 不支援啟用 SSE-C 做為儲存貯體的預設加密方法。SSE-C 是一種物件層級加密方法,可讓您在每次物件上傳或下載請求時,將加密金鑰提供給 Amazon S3。Amazon S3 使用此金鑰在請求期間加密或解密物件,然後捨棄金鑰。這表示 SSE-C 是以每個物件為基礎啟用,而不是做為預設儲存貯體設定。

支援使用 SSE-C 寫入資料的 Amazon S3 動作

您可以使用下列 API 操作或動作,在將物件寫入一般用途儲存貯體時,使用客戶提供的金鑰 (SSE-C) 請求伺服器端加密:

注意

S3 複寫支援使用 SSE-C 加密的物件。如需複寫加密物件的詳細資訊,請參閱 複寫加密的物件 (SSE-S3、SSE-KMS、DSSE-KMS、SSE-C)

SSE-C 物件加密和解密請求所需的 S3 API 標頭

您必須提供下列三個 API 標頭,以使用 SSE-C 加密或解密物件:

  • x-amz-server-side-encryption-customer-algorithm 使用此標頭來指定加密演算法。標頭值必須是 AES256。

  • x-amz-server-side-encryption-customer-key 使用此標頭提供 256 位元的 base64 編碼加密金鑰,讓 Amazon S3 用來加密或解密您的資料。

  • x-amz-server-side-encryption-customer-key-MD5 使用此標頭可根據 RFC 1321 提供加密金鑰的 base64 編碼 128 位元 MD5 摘要。Amazon S3 使用此標頭來進行訊息完整性檢查,以確保加密金鑰傳輸無誤。

請求複製使用 SSE-C 加密的來源物件所需的 S3 API 標頭

您必須提供下列三個 API 標頭,才能複製使用 SSE-C 加密的來源物件:

  • x-amz-copy-source-server-side-encryption-customer-algorithm 包含此標頭來指定 Amazon S3 應該用來解密來源物件的演算法。此值必須是 AES256。

  • x-amz-copy-source-server-side-encryption-customer-key 包含此標頭以提供 base64 編碼的加密金鑰,讓 Amazon S3 用來解密來源物件。此加密金鑰必須是您建立來源物件時提供給 Amazon S3 的加密金鑰。否則,Amazon S3 無法解密物件。

  • x-amz-copy-source-server-side-encryption-customer-key-MD5 包含此標頭,以提供根據 RFC 1321 加密金鑰的 base64 編碼 128 位元 MD5 摘要。

強制 SSE-C 加密的儲存貯體政策範例

若要針對寫入 Amazon S3 儲存貯體的所有物件要求 SSE-C,您可以使用儲存貯體政策。例如,下列儲存貯體政策拒絕所有不包含請求 SSE-C 之 x-amz-server-side-encryption-customer-algorithm 標題請求的上傳物件 (s3:PutObject) 許可。

{ "Version":"2012-10-17", "Id": "PutObjectPolicy", "Statement": [ { "Sid": "RequireSSECObjectUploads", "Effect": "Deny", "Principal": "*", "Action": "s3:PutObject", "Resource": "arn:aws:s3:::amzn-s3-demo-bucket/*", "Condition": { "Null": { "s3:x-amz-server-side-encryption-customer-algorithm": "true" } } } ] }
重要

如果您使用儲存貯體政策在s3:PutObject 上要求 SSE-C,則必須在所有分段上傳請求中包含 x-amz-server-side-encryption-customer-algorithm 標頭 (CreateMultipartUpload、UploadPart 和 CompleteMultipartUpload)。

已預先簽章的 URL 和 SSE-C

您可以產生預先簽章的 URL,其可以用於上傳新的物件、擷取現有的物件或擷取物件中繼資料等操作。預先簽章的 URL 支援如下的 SSE-C:

  • 建立預先簽章的 URL 時,您必須在簽章計算中使用 x-amz-server-side-encryption-customer-algorithm 標頭來指定演算法。

  • 使用預先簽章的 URL 來上傳新的物件、擷取現有的物件或只擷取物件中繼資料時,您必須提供用戶端應用程式請求中的所有加密標頭。

    注意

    針對非 SSE-C 物件,您可以產生預先簽章的 URL,並將該 URL 直接貼入至瀏覽器以存取資料。

    不過,您無法針對 SSE-C 物件執行此操作,因為除了預先簽章的 URL 之外,您亦須包含 SSE-C 物件專屬的 HTTP 標頭。因此,您只能以程式設計方式針對 SSE-C 物件使用預先簽章的 URL。

如需預先簽章的 URL 詳細資訊,請參閱使用預先簽章的 URL 來下載和上傳物件

使用 SSE-C 提出請求

在使用 REST API 建立物件時,您可以使用客戶提供的金鑰 (SSE-C) 來指定伺服器端加密。使用 SSE-C 時,您必須使用 提供加密金鑰資訊請求複製使用 SSE-C 加密的來源物件所需的 S3 API 標頭。您可以使用 AWS SDK 包裝函式程式庫將這些標頭新增至您的請求。如果需要,您可以直接在應用程式中進行 Amazon S3 REST API 呼叫。

重要

使用客戶提供的金鑰 (SSE-C) 指定伺服器端加密之前,請確定不會針對一般用途儲存貯體封鎖 SSE-C 加密。如需詳細資訊,請參閱封鎖或取消封鎖一般用途儲存貯體的 SSE-C

注意

您無法使用 Amazon S3 主控台上傳物件並請求 SSE-C。 您也無法使用 主控台來更新 (例如,變更儲存類別或新增中繼資料) 使用 SSE-C 存放的現有物件。 如需詳細資訊,請參閱 SSE-C 物件加密和解密請求所需的 S3 API 標頭

使用 REST API

支援 SSE-C 的 Amazon S3 REST API APIs

下列 Amazon S3 API 支援伺服器端加密搭配客戶提供的加密金鑰 (SSE-C)。

  • GET 操作 – 使用 GET API 擷取物件時 (請參閱 GET 物件),您可以指定這些請求標頭。

  • HEAD 操作 – 若要使用 HEAD API 擷取物件中繼資料 (請參閱 HEAD 物件),您可以指定這些請求標頭。

  • PUT 操作 – 使用 PUT API 上傳資料時 (請參閱 PUT 物件),您可以指定這些請求標頭。

  • 分段上傳 – 使用分段上傳 API 上傳大型物件時,您可以指定這些標頭。您可以在啟動請求 (請參閱啟動分段上傳) 和每個後續分段上傳請求 (請參閱上傳組件UploadPartCopy) 中指定這些標頭。每個部分上傳要求的加密資訊,必須與您在啟動分段上傳要求中所提供的加密資訊相同。

  • POST 操作 – 使用 POST 操作上傳物件時 (請參閱 POST 物件),請提供與表單欄位中相同的資訊,而不是請求標頭。

  • 複製操作 – 當您複製物件時 (請參閱 CopyObject),您同時擁有來源物件和目標物件:

使用 AWS SDKs為 PUT、GET、頭部和複製操作指定 SSE-C

下列範例說明如何用客戶提供金鑰 (SSE-C),要求為物件進行伺服器端加密。這些範例會執行下列操作。每個操作示範如何在要求中指定 SSE-C 相關標頭:

  • 放置物件 – 使用客戶提供的加密金鑰上傳物件並請求伺服器端加密。

  • 取得物件 – 下載前一個步驟中所上傳的物件。在此請求中,請您提供在您上傳物件時所提供的相同加密資訊。Amazon S3 需要此資訊來解密物件,才能將物件傳回給您。

  • 取得物件中繼資料 – 擷取物件的中繼資料。請您提供物件建立時,使用的加密資訊。

  • 複製物件 – 建立先前上傳物件的複本。因為來源物件是使用 SSE-C 所存放,所以您必須在複製要求中提供其加密資訊。根據預設,只有在您明確請求加密時,Amazon S3 才會加密物件的複本。此範例指示 Amazon S3 存放加密的物件複本。

Java
注意

此範例示範如何以單一操作上傳物件。使用分段上傳 API 上傳大型物件時,請您提供如此範例一樣的加密資訊。如需使用 的分段上傳範例 AWS SDK for Java,請參閱 使用分段上傳來上傳物件

新增要求加密資訊,您可包含 SSECustomerKey 在您的要求中。如需有關 SSECustomerKey 類別的詳細資訊,請參閱 REST API 一節。

如需建立和測試工作範例的說明,請參閱《 AWS SDK for Java 開發人員指南》中的入門

範例
import com.amazonaws.AmazonServiceException; import com.amazonaws.SdkClientException; import com.amazonaws.auth.profile.ProfileCredentialsProvider; import com.amazonaws.regions.Regions; import com.amazonaws.services.s3.AmazonS3; import com.amazonaws.services.s3.AmazonS3ClientBuilder; import com.amazonaws.services.s3.model.*; import javax.crypto.KeyGenerator; import java.io.BufferedReader; import java.io.File; import java.io.IOException; import java.io.InputStreamReader; import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; public class ServerSideEncryptionUsingClientSideEncryptionKey { private static SSECustomerKey SSE_KEY; private static AmazonS3 S3_CLIENT; private static KeyGenerator KEY_GENERATOR; public static void main(String[] args) throws IOException, NoSuchAlgorithmException { Regions clientRegion = Regions.DEFAULT_REGION; String bucketName = "*** Bucket name ***"; String keyName = "*** Key name ***"; String uploadFileName = "*** File path ***"; String targetKeyName = "*** Target key name ***"; // Create an encryption key. KEY_GENERATOR = KeyGenerator.getInstance("AES"); KEY_GENERATOR.init(256, new SecureRandom()); SSE_KEY = new SSECustomerKey(KEY_GENERATOR.generateKey()); try { S3_CLIENT = AmazonS3ClientBuilder.standard() .withCredentials(new ProfileCredentialsProvider()) .withRegion(clientRegion) .build(); // Upload an object. uploadObject(bucketName, keyName, new File(uploadFileName)); // Download the object. downloadObject(bucketName, keyName); // Verify that the object is properly encrypted by attempting to retrieve it // using the encryption key. retrieveObjectMetadata(bucketName, keyName); // Copy the object into a new object that also uses SSE-C. copyObject(bucketName, keyName, targetKeyName); } catch (AmazonServiceException e) { // The call was transmitted successfully, but Amazon S3 couldn't process // it, so it returned an error response. e.printStackTrace(); } catch (SdkClientException e) { // Amazon S3 couldn't be contacted for a response, or the client // couldn't parse the response from Amazon S3. e.printStackTrace(); } } private static void uploadObject(String bucketName, String keyName, File file) { PutObjectRequest putRequest = new PutObjectRequest(bucketName, keyName, file).withSSECustomerKey(SSE_KEY); S3_CLIENT.putObject(putRequest); System.out.println("Object uploaded"); } private static void downloadObject(String bucketName, String keyName) throws IOException { GetObjectRequest getObjectRequest = new GetObjectRequest(bucketName, keyName).withSSECustomerKey(SSE_KEY); S3Object object = S3_CLIENT.getObject(getObjectRequest); System.out.println("Object content: "); displayTextInputStream(object.getObjectContent()); } private static void retrieveObjectMetadata(String bucketName, String keyName) { GetObjectMetadataRequest getMetadataRequest = new GetObjectMetadataRequest(bucketName, keyName) .withSSECustomerKey(SSE_KEY); ObjectMetadata objectMetadata = S3_CLIENT.getObjectMetadata(getMetadataRequest); System.out.println("Metadata retrieved. Object size: " + objectMetadata.getContentLength()); } private static void copyObject(String bucketName, String keyName, String targetKeyName) throws NoSuchAlgorithmException { // Create a new encryption key for target so that the target is saved using // SSE-C. SSECustomerKey newSSEKey = new SSECustomerKey(KEY_GENERATOR.generateKey()); CopyObjectRequest copyRequest = new CopyObjectRequest(bucketName, keyName, bucketName, targetKeyName) .withSourceSSECustomerKey(SSE_KEY) .withDestinationSSECustomerKey(newSSEKey); S3_CLIENT.copyObject(copyRequest); System.out.println("Object copied"); } private static void displayTextInputStream(S3ObjectInputStream input) throws IOException { // Read one line at a time from the input stream and display each line. BufferedReader reader = new BufferedReader(new InputStreamReader(input)); String line; while ((line = reader.readLine()) != null) { System.out.println(line); } System.out.println(); } }
.NET
注意

如需更說使用分段上傳 API 大型物件的範例,請參閱 使用分段上傳來上傳物件使用 AWS SDKs(低階 API)

如需有關設定和執行程式碼範例的資訊,請參閱《適用於 .NET 的 AWS SDK 開發人員指南》中的適用於 .NET 的 SDK 入門AWS

範例
using Amazon; using Amazon.S3; using Amazon.S3.Model; using System; using System.IO; using System.Security.Cryptography; using System.Threading.Tasks; namespace Amazon.DocSamples.S3 { class SSEClientEncryptionKeyObjectOperationsTest { private const string bucketName = "*** bucket name ***"; private const string keyName = "*** key name for new object created ***"; private const string copyTargetKeyName = "*** key name for object copy ***"; // Specify your bucket region (an example region is shown). private static readonly RegionEndpoint bucketRegion = RegionEndpoint.USWest2; private static IAmazonS3 client; public static void Main() { client = new AmazonS3Client(bucketRegion); ObjectOpsUsingClientEncryptionKeyAsync().Wait(); } private static async Task ObjectOpsUsingClientEncryptionKeyAsync() { try { // Create an encryption key. Aes aesEncryption = Aes.Create(); aesEncryption.KeySize = 256; aesEncryption.GenerateKey(); string base64Key = Convert.ToBase64String(aesEncryption.Key); // 1. Upload the object. PutObjectRequest putObjectRequest = await UploadObjectAsync(base64Key); // 2. Download the object and verify that its contents matches what you uploaded. await DownloadObjectAsync(base64Key, putObjectRequest); // 3. Get object metadata and verify that the object uses AES-256 encryption. await GetObjectMetadataAsync(base64Key); // 4. Copy both the source and target objects using server-side encryption with // a customer-provided encryption key. await CopyObjectAsync(aesEncryption, base64Key); } catch (AmazonS3Exception e) { Console.WriteLine("Error encountered ***. Message:'{0}' when writing an object", e.Message); } catch (Exception e) { Console.WriteLine("Unknown encountered on server. Message:'{0}' when writing an object", e.Message); } } private static async Task<PutObjectRequest> UploadObjectAsync(string base64Key) { PutObjectRequest putObjectRequest = new PutObjectRequest { BucketName = bucketName, Key = keyName, ContentBody = "sample text", ServerSideEncryptionCustomerMethod = ServerSideEncryptionCustomerMethod.AES256, ServerSideEncryptionCustomerProvidedKey = base64Key }; PutObjectResponse putObjectResponse = await client.PutObjectAsync(putObjectRequest); return putObjectRequest; } private static async Task DownloadObjectAsync(string base64Key, PutObjectRequest putObjectRequest) { GetObjectRequest getObjectRequest = new GetObjectRequest { BucketName = bucketName, Key = keyName, // Provide encryption information for the object stored in Amazon S3. ServerSideEncryptionCustomerMethod = ServerSideEncryptionCustomerMethod.AES256, ServerSideEncryptionCustomerProvidedKey = base64Key }; using (GetObjectResponse getResponse = await client.GetObjectAsync(getObjectRequest)) using (StreamReader reader = new StreamReader(getResponse.ResponseStream)) { string content = reader.ReadToEnd(); if (String.Compare(putObjectRequest.ContentBody, content) == 0) Console.WriteLine("Object content is same as we uploaded"); else Console.WriteLine("Error...Object content is not same."); if (getResponse.ServerSideEncryptionCustomerMethod == ServerSideEncryptionCustomerMethod.AES256) Console.WriteLine("Object encryption method is AES256, same as we set"); else Console.WriteLine("Error...Object encryption method is not the same as AES256 we set"); // Assert.AreEqual(putObjectRequest.ContentBody, content); // Assert.AreEqual(ServerSideEncryptionCustomerMethod.AES256, getResponse.ServerSideEncryptionCustomerMethod); } } private static async Task GetObjectMetadataAsync(string base64Key) { GetObjectMetadataRequest getObjectMetadataRequest = new GetObjectMetadataRequest { BucketName = bucketName, Key = keyName, // The object stored in Amazon S3 is encrypted, so provide the necessary encryption information. ServerSideEncryptionCustomerMethod = ServerSideEncryptionCustomerMethod.AES256, ServerSideEncryptionCustomerProvidedKey = base64Key }; GetObjectMetadataResponse getObjectMetadataResponse = await client.GetObjectMetadataAsync(getObjectMetadataRequest); Console.WriteLine("The object metadata show encryption method used is: {0}", getObjectMetadataResponse.ServerSideEncryptionCustomerMethod); // Assert.AreEqual(ServerSideEncryptionCustomerMethod.AES256, getObjectMetadataResponse.ServerSideEncryptionCustomerMethod); } private static async Task CopyObjectAsync(Aes aesEncryption, string base64Key) { aesEncryption.GenerateKey(); string copyBase64Key = Convert.ToBase64String(aesEncryption.Key); CopyObjectRequest copyRequest = new CopyObjectRequest { SourceBucket = bucketName, SourceKey = keyName, DestinationBucket = bucketName, DestinationKey = copyTargetKeyName, // Information about the source object's encryption. CopySourceServerSideEncryptionCustomerMethod = ServerSideEncryptionCustomerMethod.AES256, CopySourceServerSideEncryptionCustomerProvidedKey = base64Key, // Information about the target object's encryption. ServerSideEncryptionCustomerMethod = ServerSideEncryptionCustomerMethod.AES256, ServerSideEncryptionCustomerProvidedKey = copyBase64Key }; await client.CopyObjectAsync(copyRequest); } } }

使用 AWS SDKs為分段上傳指定 SSE-C

上節中的範例示範如何以 PUT、GET、Head 和 Copy 操作要求經由客戶提供加密金鑰的伺服器端加密 (SSE-C)。本節說明其他支援 SSE-C 的 Amazon S3 API。

Java

若要上傳大型物件,您可以使用分段上傳 APIs。如需詳細資訊,請參閱在 Amazon S3 中使用分段上傳來上傳和複製物件。您可以使用高階或低階 API 來上傳大型物件。這些 API 支援要求中的加密相關標頭。

  • 使用高階 TransferManager API 時,您可以在 中提供加密特定的標頭PutObjectRequest。如需詳細資訊,請參閱使用分段上傳來上傳物件

  • 使用低階 API 時,請您在 InitiateMultipartUploadRequest 提供加密關聯資訊,遵照 UploadPartRequest 中每一個的相同加密資訊。您不需要在 CompleteMultipartUploadRequest 提供任何加密特定標頭。如需範例,請參閱 使用 AWS SDKs(低階 API)

下列範例使用 TransferManager 建立物件,並示範如何提供 SSE-C 相關資訊。此範例執行下列操作:

  • 使用 TransferManager.upload() 方法建立物件。在PutObjectRequest執行個體中,您會在請求中提供加密金鑰資訊。Amazon S3 會使用客戶提供的金鑰來加密物件。

  • 呼叫 TransferManager.copy() 方法,以建立物件的複本。此範例指示 Amazon S3 使用新的 SSECustomerKey 來加密物件複本。因為來源物件使用 SSE-C 加密,所以 CopyObjectRequest 也會提供來源物件的加密金鑰,讓 Amazon S3 可以先解密物件,再進行複製。

範例
import com.amazonaws.AmazonServiceException; import com.amazonaws.SdkClientException; import com.amazonaws.auth.profile.ProfileCredentialsProvider; import com.amazonaws.regions.Regions; import com.amazonaws.services.s3.AmazonS3; import com.amazonaws.services.s3.AmazonS3ClientBuilder; import com.amazonaws.services.s3.model.CopyObjectRequest; import com.amazonaws.services.s3.model.PutObjectRequest; import com.amazonaws.services.s3.model.SSECustomerKey; import com.amazonaws.services.s3.transfer.Copy; import com.amazonaws.services.s3.transfer.TransferManager; import com.amazonaws.services.s3.transfer.TransferManagerBuilder; import com.amazonaws.services.s3.transfer.Upload; import javax.crypto.KeyGenerator; import java.io.File; import java.security.SecureRandom; public class ServerSideEncryptionCopyObjectUsingHLwithSSEC { public static void main(String[] args) throws Exception { Regions clientRegion = Regions.DEFAULT_REGION; String bucketName = "*** Bucket name ***"; String fileToUpload = "*** File path ***"; String keyName = "*** New object key name ***"; String targetKeyName = "*** Key name for object copy ***"; try { AmazonS3 s3Client = AmazonS3ClientBuilder.standard() .withRegion(clientRegion) .withCredentials(new ProfileCredentialsProvider()) .build(); TransferManager tm = TransferManagerBuilder.standard() .withS3Client(s3Client) .build(); // Create an object from a file. PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, keyName, new File(fileToUpload)); // Create an encryption key. KeyGenerator keyGenerator = KeyGenerator.getInstance("AES"); keyGenerator.init(256, new SecureRandom()); SSECustomerKey sseCustomerEncryptionKey = new SSECustomerKey(keyGenerator.generateKey()); // Upload the object. TransferManager uploads asynchronously, so this call // returns immediately. putObjectRequest.setSSECustomerKey(sseCustomerEncryptionKey); Upload upload = tm.upload(putObjectRequest); // Optionally, wait for the upload to finish before continuing. upload.waitForCompletion(); System.out.println("Object created."); // Copy the object and store the copy using SSE-C with a new key. CopyObjectRequest copyObjectRequest = new CopyObjectRequest(bucketName, keyName, bucketName, targetKeyName); SSECustomerKey sseTargetObjectEncryptionKey = new SSECustomerKey(keyGenerator.generateKey()); copyObjectRequest.setSourceSSECustomerKey(sseCustomerEncryptionKey); copyObjectRequest.setDestinationSSECustomerKey(sseTargetObjectEncryptionKey); // Copy the object. TransferManager copies asynchronously, so this call returns // immediately. Copy copy = tm.copy(copyObjectRequest); // Optionally, wait for the upload to finish before continuing. copy.waitForCompletion(); System.out.println("Copy complete."); } catch (AmazonServiceException e) { // The call was transmitted successfully, but Amazon S3 couldn't process // it, so it returned an error response. e.printStackTrace(); } catch (SdkClientException e) { // Amazon S3 couldn't be contacted for a response, or the client // couldn't parse the response from Amazon S3. e.printStackTrace(); } } }
.NET

若要上傳大型物件,您可以使用分段上傳 API (請參閱 在 Amazon S3 中使用分段上傳來上傳和複製物件)。 AWS SDK for .NET 提供高階或低階 APIs 來上傳大型物件。這些 API 支援要求中的加密相關標頭。

  • 使用高階 Transfer-Utility API 時,您在 TransferUtilityUploadRequest 所提供的加密特定標頭,如下所示。如需程式碼範例,請參閱 使用分段上傳來上傳物件

    TransferUtilityUploadRequest request = new TransferUtilityUploadRequest() { FilePath = filePath, BucketName = existingBucketName, Key = keyName, // Provide encryption information. ServerSideEncryptionCustomerMethod = ServerSideEncryptionCustomerMethod.AES256, ServerSideEncryptionCustomerProvidedKey = base64Key, };
  • 使用低階 API 時,請提供您在啟動分段上傳要求中的加密相關資訊,後面接著後續分段上傳要求中的相同加密資訊。您不需要在完整的分段上傳要求中提供任何加密特定標頭。如需範例,請參閱 使用 AWS SDKs(低階 API)

    以下為建立現有大型物件複本的低階分段上傳範例。在此範例中,要複製的物件會使用 SSE-C 存放在 Amazon S3 中,而您也想要使用 SSE-C 儲存目標物件。在此範例中,您要執行以下動作:

    • 提供加密金鑰與相關資訊,以啟動分段上傳要求。

    • CopyPartRequest 中提供來源與目標物件加密金鑰以及相關資訊。

    • 擷取物件中繼資料,以取得要複製之來源物件的大小。

    • 將物件分成 5 MB 部分來上傳。

    範例
    using Amazon; using Amazon.S3; using Amazon.S3.Model; using System; using System.Collections.Generic; using System.IO; using System.Security.Cryptography; using System.Threading.Tasks; namespace Amazon.DocSamples.S3 { class SSECLowLevelMPUcopyObjectTest { private const string existingBucketName = "*** bucket name ***"; private const string sourceKeyName = "*** source object key name ***"; private const string targetKeyName = "*** key name for the target object ***"; private const string filePath = @"*** file path ***"; // Specify your bucket region (an example region is shown). private static readonly RegionEndpoint bucketRegion = RegionEndpoint.USWest2; private static IAmazonS3 s3Client; static void Main() { s3Client = new AmazonS3Client(bucketRegion); CopyObjClientEncryptionKeyAsync().Wait(); } private static async Task CopyObjClientEncryptionKeyAsync() { Aes aesEncryption = Aes.Create(); aesEncryption.KeySize = 256; aesEncryption.GenerateKey(); string base64Key = Convert.ToBase64String(aesEncryption.Key); await CreateSampleObjUsingClientEncryptionKeyAsync(base64Key, s3Client); await CopyObjectAsync(s3Client, base64Key); } private static async Task CopyObjectAsync(IAmazonS3 s3Client, string base64Key) { List<CopyPartResponse> uploadResponses = new List<CopyPartResponse>(); // 1. Initialize. InitiateMultipartUploadRequest initiateRequest = new InitiateMultipartUploadRequest { BucketName = existingBucketName, Key = targetKeyName, ServerSideEncryptionCustomerMethod = ServerSideEncryptionCustomerMethod.AES256, ServerSideEncryptionCustomerProvidedKey = base64Key, }; InitiateMultipartUploadResponse initResponse = await s3Client.InitiateMultipartUploadAsync(initiateRequest); // 2. Upload Parts. long partSize = 5 * (long)Math.Pow(2, 20); // 5 MB long firstByte = 0; long lastByte = partSize; try { // First find source object size. Because object is stored encrypted with // customer provided key you need to provide encryption information in your request. GetObjectMetadataRequest getObjectMetadataRequest = new GetObjectMetadataRequest() { BucketName = existingBucketName, Key = sourceKeyName, ServerSideEncryptionCustomerMethod = ServerSideEncryptionCustomerMethod.AES256, ServerSideEncryptionCustomerProvidedKey = base64Key // " * **source object encryption key ***" }; GetObjectMetadataResponse getObjectMetadataResponse = await s3Client.GetObjectMetadataAsync(getObjectMetadataRequest); long filePosition = 0; for (int i = 1; filePosition < getObjectMetadataResponse.ContentLength; i++) { CopyPartRequest copyPartRequest = new CopyPartRequest { UploadId = initResponse.UploadId, // Source. SourceBucket = existingBucketName, SourceKey = sourceKeyName, // Source object is stored using SSE-C. Provide encryption information. CopySourceServerSideEncryptionCustomerMethod = ServerSideEncryptionCustomerMethod.AES256, CopySourceServerSideEncryptionCustomerProvidedKey = base64Key, //"***source object encryption key ***", FirstByte = firstByte, // If the last part is smaller then our normal part size then use the remaining size. LastByte = lastByte > getObjectMetadataResponse.ContentLength ? getObjectMetadataResponse.ContentLength - 1 : lastByte, // Target. DestinationBucket = existingBucketName, DestinationKey = targetKeyName, PartNumber = i, // Encryption information for the target object. ServerSideEncryptionCustomerMethod = ServerSideEncryptionCustomerMethod.AES256, ServerSideEncryptionCustomerProvidedKey = base64Key }; uploadResponses.Add(await s3Client.CopyPartAsync(copyPartRequest)); filePosition += partSize; firstByte += partSize; lastByte += partSize; } // Step 3: complete. CompleteMultipartUploadRequest completeRequest = new CompleteMultipartUploadRequest { BucketName = existingBucketName, Key = targetKeyName, UploadId = initResponse.UploadId, }; completeRequest.AddPartETags(uploadResponses); CompleteMultipartUploadResponse completeUploadResponse = await s3Client.CompleteMultipartUploadAsync(completeRequest); } catch (Exception exception) { Console.WriteLine("Exception occurred: {0}", exception.Message); AbortMultipartUploadRequest abortMPURequest = new AbortMultipartUploadRequest { BucketName = existingBucketName, Key = targetKeyName, UploadId = initResponse.UploadId }; s3Client.AbortMultipartUpload(abortMPURequest); } } private static async Task CreateSampleObjUsingClientEncryptionKeyAsync(string base64Key, IAmazonS3 s3Client) { // List to store upload part responses. List<UploadPartResponse> uploadResponses = new List<UploadPartResponse>(); // 1. Initialize. InitiateMultipartUploadRequest initiateRequest = new InitiateMultipartUploadRequest { BucketName = existingBucketName, Key = sourceKeyName, ServerSideEncryptionCustomerMethod = ServerSideEncryptionCustomerMethod.AES256, ServerSideEncryptionCustomerProvidedKey = base64Key }; InitiateMultipartUploadResponse initResponse = await s3Client.InitiateMultipartUploadAsync(initiateRequest); // 2. Upload Parts. long contentLength = new FileInfo(filePath).Length; long partSize = 5 * (long)Math.Pow(2, 20); // 5 MB try { long filePosition = 0; for (int i = 1; filePosition < contentLength; i++) { UploadPartRequest uploadRequest = new UploadPartRequest { BucketName = existingBucketName, Key = sourceKeyName, UploadId = initResponse.UploadId, PartNumber = i, PartSize = partSize, FilePosition = filePosition, FilePath = filePath, ServerSideEncryptionCustomerMethod = ServerSideEncryptionCustomerMethod.AES256, ServerSideEncryptionCustomerProvidedKey = base64Key }; // Upload part and add response to our list. uploadResponses.Add(await s3Client.UploadPartAsync(uploadRequest)); filePosition += partSize; } // Step 3: complete. CompleteMultipartUploadRequest completeRequest = new CompleteMultipartUploadRequest { BucketName = existingBucketName, Key = sourceKeyName, UploadId = initResponse.UploadId, //PartETags = new List<PartETag>(uploadResponses) }; completeRequest.AddPartETags(uploadResponses); CompleteMultipartUploadResponse completeUploadResponse = await s3Client.CompleteMultipartUploadAsync(completeRequest); } catch (Exception exception) { Console.WriteLine("Exception occurred: {0}", exception.Message); AbortMultipartUploadRequest abortMPURequest = new AbortMultipartUploadRequest { BucketName = existingBucketName, Key = sourceKeyName, UploadId = initResponse.UploadId }; await s3Client.AbortMultipartUploadAsync(abortMPURequest); } } } }