本文為英文版的機器翻譯版本,如內容有任何歧義或不一致之處,概以英文版為準。
使用伺服器端加密搭配客戶提供的金鑰 (SSE-C)
伺服器端加密是有關保護靜態資料。伺服器端加密只會加密物件資料,非物件中繼資料。透過搭配客戶提供的金鑰 (SSE-C) 使用伺服器端加密,您可以儲存使用自己的加密金鑰進行加密的資料。如果您提供的加密金鑰作為請求的一部分,Amazon S3 會在資料寫入磁碟時管理資料加密,以及在您存取物件時管理資料解密。因此,您不需要維護任何程式碼來執行資料加密與解密。您只需要管理自己提供的加密金鑰即可。
當您上傳物件時,Amazon S3 會使用您提供的加密金鑰,將 AES-256 加密套用至您的資料。然後,Amazon S3 會從記憶體中移除加密金鑰。當您擷取物件時,您必須在要求中提供相同的加密金鑰。Amazon S3 會先驗證您提供的加密金鑰是否相符,然後對物件進行解密,再將物件資料傳回給您。
使用 SSE-C 不收取額外費用。但是,設定和使用 SSE-C 的請求會產生標準 Amazon S3 請求費用。如需定價的資訊,請參閱 Amazon S3 定價。
Amazon S3 不會存放您提供的加密金鑰。相反地,它會儲存加密金鑰的隨機以雜湊為基礎的訊息驗證碼 (HMAC) 值,以驗證未來的請求。加鹽的 HMAC 值無法用來衍生加密金鑰的值,也無法用來解密加密物件的內容。換句話說,如果您遺失加密金鑰,則會遺失物件。
S3 複寫支援使用 SSE-C 加密的物件。如需複寫加密物件的詳細資訊,請參閱 複寫加密物件 (SSE-S3、SSE-KMS、DSSE-KMS、SSE-C)。
如需 SSE-C 的詳細資訊,請參閱下列主題。
SSE-C 概觀
本節提供 SSE-C 的概觀。使用 SSE-C 時,請謹記下列考量事項。
要求和限制 SSE-C
若要針對特定 Amazon S3 儲存貯體中的所有物件要求 SSE-C,您可以使用儲存貯體政策。
例如,下列儲存貯體政策拒絕上傳物件 (s3:PutObject
) 許可,以處理未包含請求 SSE-C 之x-amz-server-side-encryption-customer-algorithm
標頭的所有請求。
{
"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"
}
}
}
]
}
您也可以使用政策,限制特定 Amazon S3 儲存貯體中所有物件的伺服器端加密。例如,如果請求包含請求 SSE-C 的x-amz-server-side-encryption-customer-algorithm
標頭,則下列儲存貯體政策會拒絕對所有人的上傳物件 (s3:PutObject
) 許可。
{
"Version": "2012-10-17",
"Id": "PutObjectPolicy",
"Statement": [
{
"Sid": "RestrictSSECObjectUploads",
"Effect": "Deny",
"Principal": "*",
"Action": "s3:PutObject",
"Resource": "arn:aws:s3:::amzn-s3-demo-bucket
/*",
"Condition": {
"Null": {
"s3:x-amz-server-side-encryption-customer-algorithm": "false"
}
}
}
]
}
如果您使用儲存貯體政策在 上要求 SSE-Cs3:PutObject
,則必須在所有分段上傳請求 (CreateMultipartUpload、 UploadPart 和 CompleteMultipartUpload) 中包含 x-amz-server-side-encryption-customer-algorithm
標頭。
預先簽章的 URLs 和 SSE-C
您可以產生預先簽章的 URL,可用於上傳新物件、擷取現有物件或擷取物件中繼資料等操作。預先簽章的 URLs 支援 SSE-C,如下所示:
如需預先簽章 URLs 的詳細資訊,請參閱 使用預先簽章的 URLs 下載和上傳物件。
使用客戶提供的金鑰指定伺服器端加密 (SSE-C)
使用 REST 建立物件時API,您可以使用客戶提供的金鑰 (SSE-C) 指定伺服器端加密。使用 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
|
使用此標頭根據 MD5 1321 提供加密金鑰的 base64 編碼 128 位元 RFC 摘要。Amazon S3 使用此標頭來進行訊息完整性檢查,以確保加密金鑰傳輸無誤。
|
您可以使用 AWS SDK 包裝程式庫將這些標頭新增至您的請求。如果需要,您可以直接在應用程式中進行 Amazon S3 REST API呼叫。
您無法使用 Amazon S3 主控台上傳物件並請求 SSE-C。您也無法使用主控台更新 (例如,變更儲存類別或新增中繼資料) 使用 SSE-C 存放的現有物件。
支援 SSE-C 的 Amazon S3 靜態APIs
下列 Amazon S3 APIs 支援使用客戶提供加密金鑰 (SSE-C) 的伺服器端加密。
-
GET 操作 – 使用 GET 擷取物件時 API(請參閱 GET 物件),您可以指定請求標頭。
-
HEAD 操作 – 若要使用 HEAD 擷取物件中繼資料 API(請參閱 HEAD 物件),您可以指定這些請求標頭。
-
PUT操作 – 使用PUT物件API上傳資料時 (請參閱PUT物件),您可以指定這些請求標頭。
-
分段上傳 – 使用分段上傳 API 上傳大型物件時,您可以指定這些標頭。您可以在啟動請求 (請參閱啟動分段上傳) 及每個後續片段上傳請求 (請參閱上傳片段或上傳片段 - 複製) 中指定這些標頭。每個部分上傳要求的加密資訊,必須與您在啟動分段上傳要求中所提供的加密資訊相同。
-
POST 操作 – 使用 POST 操作上傳物件 (請參閱 POST 物件) 時,您會在表單欄位中提供相同的資訊,而非請求標頭。
-
複製操作 – 當您複製物件 (請參閱 PUT 物件 - 複製) 時,您同時擁有來源物件和目標物件:
-
如果您想要使用具有 AWS 受管金鑰的伺服器端加密來加密目標物件,則必須提供x-amz-server-side-encryption
請求標頭。
-
如果您想要使用 SSE-C 加密目標物件,您必須使用上表中所述的三個標頭提供加密資訊。
-
如果來源物件使用 SSE-C 加密,您必須使用下列標頭提供加密金鑰資訊,以便 Amazon S3 可以解密物件以進行複製。
名稱 |
描述 |
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
|
包含此標頭,以提供根據 MD5 1321 加密金鑰的 base64 編碼 128 位元 RFC 摘要。
|
下列範例示範如何使用客戶提供的金鑰 (SSE-C) 請求物件的伺服器端加密。這些範例會執行下列操作。每個操作都會示範如何在請求中指定 SSE-C-related 標頭:
-
放置物件 – 使用客戶提供的加密金鑰上傳物件並請求伺服器端加密。
-
取得物件 – 下載前一個步驟中所上傳的物件。在此請求中,請您提供在您上傳物件時所提供的相同加密資訊。Amazon S3 需要此資訊來解密物件,才能將物件傳回給您。
-
取得物件中繼資料 – 擷取物件的中繼資料。請您提供物件建立時,使用的加密資訊。
-
複製物件 – 建立先前上傳物件的複本。由於來源物件是使用 SSE-C 儲存,因此您必須在複製請求中提供其加密資訊。根據預設,只有在您明確請求加密時,Amazon S3 才會加密物件的複本。此範例指示 Amazon S3 存放加密的物件複本。
- Java
-
此範例示範如何以單一操作上傳物件。使用分段上傳API上傳大型物件時,您會以本範例所示的相同方式提供加密資訊。如需使用 的分段上傳範例 AWS SDK for Java,請參閱 使用分段上傳來上傳物件。
新增要求加密資訊,您可包含 SSECustomerKey
在您的要求中。如需有關 SSECustomerKey
類別的詳細資訊,請參閱 REST API。
如需 SSE-C 的相關資訊,請參閱 使用伺服器端加密搭配客戶提供的金鑰 (SSE-C)。如需建立和測試工作範例的說明,請參閱 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
-
如需 SSE-C 的相關資訊,請參閱 使用伺服器端加密搭配客戶提供的金鑰 (SSE-C)。如需有關設定和執行程式碼範例的資訊,請參閱 AWS SDK for .NET 中的 Word for .Word 入門 AWS SDK NET 開發人員指南。
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);
}
}
}
上一節中的範例說明如何在 PUT、SSE、Head 和 Copy 操作中使用客戶提供的金鑰 (GET-C) 請求伺服器端加密。本節說明支援 APIs-C 的其他 Amazon S3 SSE。
- Java
-
若要上傳大型物件,您可以使用分段上傳 API (請參閱 使用分段上傳來上傳和複製物件)。您可以使用高階或低階 APIs 來上傳大型物件。這些 APIs 支援請求中的加密相關標頭。
-
使用高階 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 (請參閱 使用分段上傳來上傳和複製物件)。 AWS SDK for .NET 提供高階或低階 APIs 來上傳大型物件。這些 APIs 支援請求中的加密相關標頭。
-
使用高階 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 儲存目標物件。在範例中,您可以執行下列動作:
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);
}
}
}
}