Como usar criptografia do lado do servidor com chaves fornecidas pelo cliente (SSE-C)
A criptografia de servidor envolve a proteção de dados em repouso. A criptografia no lado do servidor criptografa somente os dados de objeto, não os metadados de objeto. Ao usar a criptografia do lado do servidor com chaves fornecidas pelo cliente (SSE-C), você pode armazenar dados criptografados com suas próprias chaves de criptografia. Com a chave de criptografia que você fornece como parte de sua solicitação, o Amazon S3 gerencia a criptografia de dados ao gravar em discos, e a descriptografia dos dados quando você acessa seus objetos. Portanto, você não precisa manter um código para executar a criptografia e a descriptografia de dados. A única coisa que você precisa fazer é gerenciar as chaves de criptografia fornecidas.
Quando você faz upload de um objeto, o Amazon S3 usa a chave de criptografia fornecida para aplicar a criptografia AES-256 aos seus dados. Depois, o Amazon S3 remove a chave de criptografia da memória. Quando você recupera um objeto, deve fornecer a mesma chave de criptografia como parte de sua solicitação. O Amazon S3 primeiro verifica se a chave de criptografia fornecida é correspondente, depois decifra o objeto antes de retornar os dados de objeto.
Não há cobranças adicionais pelo uso de SSE-C. No entanto, as solicitações para configurar e usar SSE-C incorrem em cobranças padrão de solicitação do Amazon S3. Para obter mais informações sobre preços, consulte Preços do Amazon S3.
O Amazon S3 não armazena a chave de criptografia que você fornece. Em vez disso, ele armazena um valor de código de autenticação de mensagens por hash (HMAC) com salt aleatório da chave de criptografia para validar solicitações futuras. O valor de HMAC com salt não pode ser usado para derivar o valor da chave de criptografia ou para decifrar o conteúdo do objeto criptografado. Isso significa que, se você perder a chave de criptografia, perderá o objeto.
A replicação do S3 oferece suporte a objetos que são criptografados com SSE-C. Para obter mais informações sobre replicação de objetos criptografados, consulte Replicar objetos criptografados (SSE-S3, SSE-KMS, DSSE-KMS, SSE-C).
Para obter mais informações sobre SSE-C, consulte os tópicos a seguir.
Visão geral do SSE-C
Esta seção fornece uma visão geral da SSE-C. Ao usar SSE-C, tenha as seguintes considerações em mente:
-
Você deve usar HTTPS.
O Amazon S3 rejeitará todas as solicitações feitas por HTTP ao usar SSE-C. Por questões de segurança, recomendamos considerar que todas as chaves enviadas erroneamente por HTTP estão comprometidas. Descarte a chave e alterne conforme apropriado.
-
A etiqueta de entidade (ETag) na resposta não é o hash MD5 dos dados de objeto.
-
Você gerencia um mapeamento cuja chave de criptografia foi usada para criptografar objetos. O Amazon S3 não armazena chaves de criptografia. Você é responsável por acompanhar a chave de criptografia que forneceu para um objeto.
-
Se seu bucket tiver versionamento habilitado, cada versão de objeto carregada usando esse recurso poderá ter sua própria chave de criptografia. Você é responsável por acompanhar a chave de criptografia usada para uma versão de objeto.
-
Como gerencia chaves de criptografia no lado do cliente, você gerencia todas as proteções adicionais, como a alternância de chave, no lado do cliente.
Se você perder a chave de criptografia, qualquer solicitação GET
de um objeto sem chave de criptografia falhará e você perderá o objeto.
Exigência e restrição de SSE-C
Para exigir SSE-C de todos os objetos em um bucket específico do Amazon S3, use uma política de bucket.
Por exemplo, a política de bucket a seguir nega permissões para upload de objeto (s3:PutObject
) a todas as solicitações que não incluam o cabeçalho x-amz-server-side-encryption-customer-algorithm
que solicita SSE-C.
{
"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"
}
}
}
]
}
Você também pode usar uma política para restringir a criptografia do lado do servidor de todos os objetos em um bucket específico do Amazon S3. Por exemplo, a política de bucket a seguir nega permissão de upload de objeto (s3:PutObject
) para todos se a solicitação inclui o cabeçalho x-amz-server-side-encryption-customer-algorithm
solicitando SSE-C.
{
"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"
}
}
}
]
}
Se você usar uma política de bucket para exigir SSE-C em s3:PutObject
, deverá incluir o cabeçalho x-amz-server-side-encryption-customer-algorithm
em todas as solicitações de carregamento fracionado (CreateMultipartUpload, UploadPart e CompleteMultipartUpload).
Pre-signed URLs e SSE-C
Você pode gerar um URL pré-assinado que pode ser usado para operações, como fazer upload de um objeto novo, recuperar um objeto existente ou recuperar metadados de objeto. Os URLs pré-assinados oferecem suporte a SSE-C da seguinte maneira:
-
Ao criar um URL pré-assinado, você deve especificar o algoritmo usando o cabeçalho x-amz-server-side-encryption-customer-algorithm
no cálculo de assinatura.
-
Ao usar o URL pré-assinado para fazer upload de um objeto novo, recuperar um objeto existente ou recuperar somente metadados de objeto, você deve fornecer todos os cabeçalhos de criptografia na solicitação de aplicação cliente.
Para objetos que não usam SSE-C, é possível gerar um URL pré-assinado e colá-lo diretamente em um navegador para acessar os dados.
No entanto, não é possível fazer isso para objetos SSE-C porque, além do URL pré-assinado, você também precisa incluir cabeçalhos HTTP específicos para objetos SSE-C. Dessa forma, é possível usar URLs pré-assinados para objetos SSE-C somente de maneira programática.
Para obter mais informações sobre pre-signed URLs, consulte Baixar e fazer upload de objetos com URLs pré-assinados.
Especificação de criptografia no lado do servidor com chaves fornecidas pelo cliente (SSE-C).
No momento da criação do objeto com a API REST, você pode especificar a criptografia do lado do servidor com chaves fornecidas pelo cliente (SSE-C). Ao usar o SSE-C, você deve fornecer informações da chave de encriptação utilizando os cabeçalhos de pedido a seguir.
Nome |
Descrição |
x-amz-server-side-encryption-customer-algorithm
|
Use esse cabeçalho para especificar o algoritmo de criptografia. O valor do cabeçalho deve ser AES256 .
|
x-amz-server-side-encryption-customer-key
|
Use esse cabeçalho para fornecer a chave de criptografia com codificação base64 de 256 bits para o Amazon S3 a ser usada para criptografar ou descriptografar seus dados.
|
x-amz-server-side-encryption-customer-key-MD5
|
Use esse cabeçalho para fornecer o resumo MD5 com codificação base64 de 128 bits da chave de criptografia de acordo com RFC 1321. O Amazon S3 usa esse cabeçalho para fazer uma verificação de integridade de mensagens e conferir se a chave de criptografia foi transmitida sem erros.
|
Você pode usar bibliotecas de wrapper do AWS SDK para adicionar esses cabeçalhos à sua solicitação. Se precisar, você pode fazer com que a API REST do Amazon S3 seja chamada diretamente na aplicação.
Não é possível usar o console do Amazon S3 para fazer upload de um objeto e solicitar SSE-C. Também não é possível usar o console para atualizar (por exemplo, alterar a classe de armazenamento ou adicionar metadados) um objeto armazenado com o SSE-C.
APIs REST do Amazon S3 que oferecem suporte ao SSE-C
As APIs do Amazon S3 a seguir oferecem suporte à criptografia pelo servidor com chaves de criptografia fornecidas pelo cliente (SSE-C).
-
Operação GET: ao recuperar objetos usando a API GET (consulte GET Object), você pode especificar os cabeçalhos da solicitação.
-
Operação HEAD: para recuperar metadados de objeto usando a API HEAD (consulte HEAD Object), você pode especificar esses cabeçalhos de solicitação.
-
Operação PUT: ao fazer upload de dados usando a API PUT (consulte PUT Object), você pode especificar esses cabeçalhos de solicitação.
-
Carregamento fracionado: ao fazer upload de objetos grandes usando a API de carregamentos fracionados, você pode especificar esses cabeçalhos. Especifique esses cabeçalhos na solicitação de inicialização (consulte Iniciar carregamento fracionado) e em cada solicitação de upload de parte subsequente (consulte Fazer upload de parte ou Fazer upload de parte: cópia). Para cada solicitação de upload de parte, as informações de criptografia devem ser as mesmas que você forneceu na solicitação iniciada do multipart upload.
-
Operação POST: ao usar uma operação POST para fazer upload de um objeto (consulte Objeto POST), em vez dos cabeçalhos de solicitação, você fornece as mesmas informações nos campos de formulário.
-
Operação de cópia: quando você copia um objeto (consulte Objeto PUT - Copiar), tem um objeto de origem e um objeto de destino.
-
Se você quiser que o objeto de destino seja criptografado usando criptografia de servidor com chaves gerenciadas pela AWS, forneça o cabeçalho de solicitação x-amz-server-side-encryption
.
-
Se você quiser que o objeto de destino seja criptografado usando SSE-C, forneça informações de criptografia usando os três cabeçalhos descritos na tabela anterior.
-
Se o objeto de origem for criptografado usando SSE-C, você deverá fornecer informações de chave de criptografia usando os seguintes cabeçalhos para que o Amazon S3 possa descriptografar o objeto para cópia.
Nome |
Descrição |
x-amz-copy-source-server-side-encryption-customer-algorithm
|
Inclua esse cabeçalho para especificar o algoritmo que o Amazon S3 deve usar para decifrar o objeto de origem. Esse valor deve ser AES256 .
|
x-amz-copy-source-server-side-encryption-customer-key
|
Inclua esse cabeçalho para fornecer a chave de criptografia com codificação base64 para o Amazon S3 a ser usada para descriptografar o objeto de origem. Essa chave de criptografia deve ser a que você forneceu ao Amazon S3 quando criou o objeto de origem. Caso contrário, o Amazon S3 não pode descriptografar o objeto.
|
x-amz-copy-source-server-side-encryption-customer-key-MD5
|
Inclua esse cabeçalho para fornecer o resumo MD5 com codificação base64 de 128 bits da chave de criptografia, de acordo com RFC 1321.
|
O exemplo a seguir mostra como solicitar a criptografia de servidor com chaves fornecidas pelo cliente (SSE-C) para objetos. Os exemplos executam as seguintes operações. Cada operação mostra como especificar cabeçalhos relacionados a SSE-C na solicitação:
-
Colocar objeto: faz upload de um objeto e solicita a criptografia de servidor, usando uma chave de criptografia fornecida pelo cliente.
-
Obter objeto: faz download do objeto carregado na etapa anterior. Na solicitação, você fornece as mesmas informações de criptografia fornecidas quando o objeto foi carregado. O Amazon S3 precisa dessas informações para descriptografar o objeto e para que ele possa ser devolvido a você.
-
Obter metadados do objeto: recupera os metadados do objeto. Você fornece as mesmas informações de criptografia usadas quando o objeto foi criado.
-
Copiar objeto: faz uma cópia de um objeto carregado anteriormente. Como o objeto de origem é armazenado usando SSE-C, você deve fornecer suas informações de criptografia na solicitação de cópia. Por padrão, o Amazon S3 criptografa a cópia do objeto somente se você solicitar explicitamente. Esse exemplo direciona o Amazon S3 a armazenar uma cópia criptografada do objeto.
- Java
-
Este exemplo mostra como fazer upload de um objeto em uma única operação. Ao usar a API de Multipart Upload para fazer upload de objetos grandes, você fornece informações de criptografia da mesma maneira que exibidas nesse exemplo. Para exemplos de carregamentos fracionados usando o AWS SDK for Java, consulte Fazer upload de um objeto usando multipart upload.
Para adicionar informações necessárias de criptografia, inclua uma SSECustomerKey
na solicitação. Para obter mais informações sobre a classe SSECustomerKey
, consulte a seção REST API.
Para obter informações sobre SSE-C, consulte Como usar criptografia do lado do servidor com chaves fornecidas pelo cliente (SSE-C). Consulte instruções sobre como criar e testar uma amostra funcional em Getting Started no Guia do desenvolvedor do 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
-
Para obter informações sobre SSE-C, consulte Como usar criptografia do lado do servidor com chaves fornecidas pelo cliente (SSE-C). Para obter informações sobre como configurar e executar exemplos de código, consulte Conceitos básicos do AWS SDK for .NET no Guia do desenvolvedor do AWS SDK for .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);
}
}
}
O exemplo da seção anterior mostra como solicitar a criptografia de servidor com a chave fornecida pelo cliente (SSE-C) nas operações PUT, GET, Head e Copy. Esta seção descreve outras APIs do Amazon S3 que oferecem suporte para SSE-C.
- Java
-
Para carregar objetos grandes, você pode usar a API de carregamento fracionado (consulte Carregar e copiar objetos usando multipart upload). Você pode usar APIs de alto ou baixo nível para fazer upload de objetos grandes. Essas APIs oferecem suporte para cabeçalhos relacionados à criptografia na solicitação.
-
Ao usar a API do TransferManager
de alto nível, você fornece os cabeçalhos específicos de criptografia na PutObjectRequest
(consulte Fazer upload de um objeto usando multipart upload).
-
Ao usar a API de baixo nível, você fornece informações relacionadas à criptografia na InitiateMultipartUploadRequest
, seguidas por informações de criptografia idênticas em cada UploadPartRequest
. Você não precisa fornecer cabeçalhos específicos de criptografia na CompleteMultipartUploadRequest
. Para ver exemplos, consulte Usar os AWS SDKs (API de baixo nível).
O exemplo a seguir usa TransferManager
para criar objetos e mostra como fornecer informações relacionadas a SSE-C. O exemplo faz o seguinte:
-
Cria um objeto usando o método TransferManager.upload()
. Na instância PutObjectRequest
, você fornece informações de chave de criptografia para solicitar. O Amazon S3 criptografa o objeto usando a chave fornecida pelo cliente.
-
Faz uma cópia do objeto, chamando o método TransferManager.copy()
. O exemplo instrui o Amazon S3 a criptografar a cópia do objeto usando um novo SSECustomerKey
. Como o objeto de origem é criptografado usando SSE-C, o CopyObjectRequest
também fornece a chave de criptografia do objeto de origem para que o Amazon S3 possa descriptografar o objeto antes de copiá-lo.
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
-
Para carregar objetos grandes, você pode usar a API de carregamentos fracionados (consulte Carregar e copiar objetos usando multipart upload). AWS O SDK for .NET fornece APIs de alto ou baixo nível para fazer upload de objetos grandes. Essas APIs oferecem suporte para cabeçalhos relacionados à criptografia na solicitação.
-
Ao usar a API do Transfer-Utility
de alto nível, você fornece os cabeçalhos específicos de criptografia na TransferUtilityUploadRequest
, conforme mostrado. Para obter exemplos de código, consulte Fazer upload de um objeto usando multipart upload.
TransferUtilityUploadRequest request = new TransferUtilityUploadRequest()
{
FilePath = filePath,
BucketName = existingBucketName,
Key = keyName,
// Provide encryption information.
ServerSideEncryptionCustomerMethod = ServerSideEncryptionCustomerMethod.AES256,
ServerSideEncryptionCustomerProvidedKey = base64Key
,
};
-
Ao usar a API de baixo nível, você fornece informações relacionadas à criptografia na solicitação para iniciar o multipart upload, seguidas por informações de criptografia idênticas nas solicitações subsequentes de upload de parte. Você não precisa fornecer cabeçalhos específicos de criptografia na solicitação de multipart upload completo. Para ver exemplos, consulte Usar os AWS SDKs (API de baixo nível).
O seguinte é um exemplo de multipart upload de baixo nível que faz uma cópia de um objeto grande existente. No exemplo, o objeto a ser copiado é armazenado no Amazon S3 usando o SSE-C, e você deseja salvar o objeto de destino também usando o SSE-C. No exemplo, faça o seguinte:
-
Inicie uma solicitação de multipart upload fornecendo uma chave de criptografia e as informações relacionadas.
-
Forneça as chaves de criptografia de objeto de origem e de destino e as informações relacionadas na CopyPartRequest
.
-
Obtenha o tamanho do objeto de origem a ser copiado recuperando os metadados do objeto.
-
Faça upload dos objetos em partes de 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);
}
}
}
}