Uso de cifrado en el lado del servidor con claves proporcionadas por el cliente (SSE-C)
El cifrado en el servidor consiste en proteger los datos en reposo. El cifrado en el servidor solo cifra los datos de objetos, no los metadatos de objetos. Mediante el cifrado del servidor con claves proporcionadas por el cliente (SSE-C) puede almacenar los datos cifrados con sus propias claves de cifrado. Con la clave de cifrado que proporcione como parte de su solicitud, Amazon S3 administra tanto el cifrado de datos, al escribir en los discos, como el descifrado de datos, al obtener acceso a los objetos. Por tanto, no ha de mantener ningún código para llevar a cabo el cifrado y el descifrado de los datos. Lo único que tiene que hacer es administrar las claves de cifrado que proporcione.
Cuando carga un objeto, Amazon S3 usa la clave de cifrado facilitada para aplicar un cifrado AES-256 a los datos. A continuación, Amazon S3 elimina la clave de cifrado de la memoria. Al recuperar un objeto, debe facilitar la misma clave de cifrado como parte de la solicitud. En primer lugar, Amazon S3 comprueba que la clave de cifrado proporcionada coincida, y a continuación descifra el objeto antes de devolverle los datos del mismo.
El uso de SSE-C no tiene costes adicionales. Sin embargo, las solicitudes de configuración y uso de SSE-C incurren en cargos estándar de solicitud de Amazon S3. Para obtener información acerca de los precios, consulte Precios de Amazon S3.
Amazon S3 no almacena la clave de cifrado que facilite. En su lugar, almacena un valor de código de autenticación de mensajes basado en hash (HMAC) discontinuo aleatorio de la clave de cifrado para validar las solicitudes futuras. El valor HMAC "salted" no se puede usar para derivar el valor de la clave de cifrado ni para descifrar los contenidos del objeto cifrado. Esto implica que, si pierde la clave de cifrado, habrá perdido el objeto.
La replicación de S3 admite objetos cifrados con SSE-C. Para obtener más información sobre la replicación de objetos cifrados, consulte Replicación de objetos cifrados (SSE-S3, SSE-KMS, DSSE-KMS, SSE-C).
Para obtener más información acerca de SSE-C, vea los temas siguientes.
Información general de SSE-C
En esta sección, se proporciona información general acerca del SSE-C. Cuando utilice SSE-C, tenga en cuenta las siguientes consideraciones.
-
Debe utilizar HTTPS.
Amazon S3 rechaza cualquier solicitud que se realice por HTTP cuando use SSE-C. Por motivos de seguridad, le recomendamos que tenga en cuenta que cualquier clave que envíe por error sobre HTTP podría estar en peligro. Descarte la clave y practique la rotación apropiada.
-
La etiqueta de entidad (ETag) de la respuesta no es el MD5 de los datos del objeto.
-
Debe administrar el mapeo de qué clave de cifrado se utiliza para cifrar cada objeto. Amazon S3 no almacena claves de cifrado. Usted debe responsabilizarse de realizar un seguimiento de qué clave de cifrado proporciona para cada objeto.
-
Si su bucket tiene activado el control de versiones, cada versión del objeto que cargue utilizando esta característica tendrá su propia clave de cifrado. Usted debe responsabilizarse de realizar un seguimiento de qué clave de cifrado se ha utilizado en cada versión del objeto.
-
Dado que es usted quien administra las claves de cifrado en el cliente, ha de administrar todas las garantías adicionales, como la rotación de claves, en el lado del cliente.
Si pierde la clave de cifrado, todas las solicitudes GET
de un objeto sin su clave de cifrado provoca un error y pierde el objeto.
Exigir y restringir SSE-C
Para requerir SSE-C para todos los objetos en un bucket de Amazon S3 particular, utilice una política de bucket.
Por ejemplo, la siguiente política de bucket deniega la carga de objetos (s3:PutObject
) para todas las solicitudes que no incluyan el encabezado 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"
}
}
}
]
}
También puede utilizar una política para restringir el cifrado del lado del servidor para todos los objetos en un bucket de Amazon S3 particular. Por ejemplo, la siguiente política de bucket deniega el permiso de carga de objeto (s3:PutObject
) para todos, si la solicitud incluye el encabezado x-amz-server-side-encryption-customer-algorithm
que solicita 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"
}
}
}
]
}
Si utiliza una política de bucket para exigir SSE-C en s3:PutObject
, debe incluir el encabezado x-amz-server-side-encryption-customer-algorithm
en todas las solicitudes de carga multiparte (CreateMultipartUpload, UploadPart y CompleteMultipartUpload).
URL prefirmadas y SSE-C
Puede generar una URL prefirmada, que podrá utilizar para operaciones como la carga de un nuevo objeto, la recuperación de un objeto existente o la recuperación de metadatos de objetos. Las URL prefirmadas se usan con el SSE-C de la siguiente forma:
-
Al crear una URL prefirmada, debe especificar el algoritmo utilizando el encabezado x-amz-server-side-encryption-customer-algorithm
en el cálculo de la firma.
-
Al usar la URL prefirmada para cargar un objeto nuevo, recuperar un objeto existente o recuperar solo metadatos de objetos, debe facilitar todos los encabezados de cifrado en su solicitud de aplicación cliente.
Para objetos no SSE-C, puede generar una URL prefirmada y pegar dicha URL directamente en un navegador para acceder a los datos.
No obstante, no puede hacer esto en objetos SSE-C porque además de la URL prefirmada también debe incluir encabezamientos de HTTP específicos de objetos SSE-C Por tanto, puede usar las URL prefirmadas para objetos SSE-C solo mediante programación.
Para obtener más información acerca de URL prefirmadas, consulte Descarga y carga de objetos con URL prefirmadas.
Especificación del cifrado del lado del servidor con claves proporcionadas por el cliente (SSE-C)
En el momento de la creación de objetos con la API de REST, puede especificar el cifrado del lado del servidor con claves proporcionadas por el cliente (SSE-C). Cuando utilice SSE-C, deberá proporcionar información sobre la clave de cifrado mediante los siguientes encabezados de solicitud.
Nombre |
Descripción |
x-amz-server-side-encryption-customer-algorithm
|
Use este encabezado para especificar el algoritmo de cifrado. El valor del encabezado ha de ser AES256 .
|
x-amz-server-side-encryption-customer-key
|
Use este encabezado para facilitar la clave de cifrado de 256 bits con codificación base64 para que Amazon S3 pueda usarla para cifrar o descifrar los datos.
|
x-amz-server-side-encryption-customer-key-MD5
|
Use este encabezado para facilitar el resumen MD5 de 128 bits con codificación en base64 de la clave de cifrado, según la RFC 1321. Amazon S3 usa este encabezado para comprobar la integridad del mensaje y garantizar que la clave de cifrado se haya transmitido sin errores.
|
Puede usar las bibliotecas de encapsulamiento del AWS SDK para agregar estos encabezados a su solicitud. Si lo necesita, también puede realizar las llamadas a la API de REST de Amazon S3 directamente en su aplicación.
No puede usar la consola de Amazon S3 para cargar un objeto y solicitar SSE-C. Tampoco puede usar la consola para actualizar (por ejemplo: cambiar la clase de almacenamiento o agregar metadatos) un objeto existente almacenado con SSE-C.
API de REST de Amazon S3 que admiten SSE-C
Las siguientes API de Amazon S3 admiten el cifrado del lado del servidor con claves de cifrado (SSE-C) proporcionadas por el cliente.
-
Operación GET: cuando recupera datos con la API GET (consulte GET Object), puede especificar los encabezados de solicitud.
-
Operación HEAD: para recuperar metadatos de objetos con la API HEAD (consulte HEAD Object), puede especificar estos encabezados de solicitud.
-
Operación PUT: cuando carga datos con la API de PUT Object (consulte PUT Object), puede especificar estos encabezados de solicitud.
-
Carga multiparte: al cargar objetos grandes mediante la API de carga multiparte, puede especificar estos encabezados. Debe especificar estos encabezados en la solicitud inicial (consulte Iniciar carga multiparte) y en cada solicitud de carga de partes subsiguiente (consulte Cargar parte o Cargar parte - Copia). Para cada solicitud de carga de parte, la información de cifrado ha de ser la misma que la facilitada en la solicitud inicial de la carga multiparte.
-
Operación POST: cuando utiliza una operación POST para cargar un objeto (consulte POST Object), en vez de proporcionar los encabezados de solicitud, debe proporcionar la misma información en los campos del formulario.
-
Operación Copy: cuando copia un objeto (consulte PUT Object - Copy), tiene un objeto de origen y uno de destino.
-
Si quiere que el objeto de destino se cifre mediante el cifrado del lado del servidor con claves administradas por AWS, debe proporcionar el encabezado de solicitud x-amz-server-side-encryption
.
-
Si quiere que el objeto objetivo se cifre mediante SSE-C, debe facilitar información de cifrado mediante los tres encabezados descritos en la tabla anterior.
-
Si el objeto de origen está cifrado con SSE-C, debe facilitar la información de la clave de cifrado mediante los siguientes encabezados, de modo que Amazon S3 puede descifrar el objeto para copiarlo.
Nombre |
Descripción |
x-amz-copy-source-server-side-encryption-customer-algorithm
|
Incluya este encabezado para especificar el algoritmo que debe usar Amazon S3 para descifrar el objeto de origen. Este valor debe ser AES256 .
|
x-amz-copy-source-server-side-encryption-customer-key
|
Incluya este encabezado para facilitar la clave de cifrado con codificación base64 para que Amazon S3 la utilice para descifrar el objeto de origen. Esta clave de cifrado debe ser la que proporcionó a Amazon S3 al crear el objeto de origen. De lo contrario, Amazon S3 no puede descifrar el objeto.
|
x-amz-copy-source-server-side-encryption-customer-key-MD5
|
Incluya este encabezado para facilitar el resumen MD5 de 128 bits con codificación en base64 de la clave de cifrado, según la RFC 1321.
|
En el siguiente ejemplo se muestra cómo solicitar el cifrado del lado del servidor con claves proporcionadas por el cliente (SSE-C) para objetos. En los ejemplos se realizan las siguientes operaciones. Cada operación muestra cómo especificar encabezados relacionados con el SSE-C en la solicitud:
-
Put object: carga un objeto y solicita el cifrado del lado del servidor mediante una clave de cifrado proporcionada por un cliente.
-
Get object: descarga el objeto que se cargó en el paso anterior. En la solicitud, proporciona la misma información de cifrado que proporcionó al cargar el objeto. Amazon S3 necesita esta información para descifrar el objeto de modo que pueda devolvérselo.
-
Get object metadata: recupera los metadatos del objeto. Proporciona la misma información de cifrado usada al crear el objeto.
-
Copy object: realiza una copia del objeto cargado previamente. Dado que el objeto de origen se almacena mediante SSE-C, usted debe proporcionar la información de cifrado en su solicitud de copia. De forma predeterminada, Amazon S3 cifra la copia del objeto solo si lo solicita explícitamente. En este ejemplo se indica a Amazon S3 que almacene una copia cifrada del objeto.
- Java
-
Este ejemplo muestra cómo cargar un objeto en una operación única. Cuando utiliza la API de carga multiparte para cargar objetos grandes, brinda información de cifrado como se muestra en el siguiente ejemplo. Para ver ejemplos de cargas multiparte que utilizan AWS SDK for Java, consulte Carga de un objeto con la carga multiparte.
Para añadir la información de cifrado necesaria, incluya una SSECustomerKey
en su solicitud. Para obtener más información sobre la clase SSECustomerKey
, consulte la sección REST API (API de REST).
Para obtener más información acerca de SSE-C, consulte Uso de cifrado en el lado del servidor con claves proporcionadas por el cliente (SSE-C). Para obtener instrucciones sobre cómo crear y probar una muestra funcional, consulte Introducción en la Guía del desarrollador de 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 obtener más información acerca de SSE-C, consulte Uso de cifrado en el lado del servidor con claves proporcionadas por el cliente (SSE-C). Para obtener información acerca de cómo configurar y ejecutar ejemplos de código, consulte Introducción al SDK de AWS para .NET en la Guía para desarrolladores del SDK de AWS para .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);
}
}
}
En el ejemplo de la sección anterior se muestra cómo solicitar cifrado del lado del servidor con claves proporcionadas por el cliente (SSE-C) en operaciones PUT, GET, Head y Copy. En esta sección se describen otras API de Amazon S3 que admiten SSE-C.
- Java
-
Para cargar objetos grandes, puede utilizar la API de carga multiparte (consulte Carga y copia de objetos con la carga multiparte). Puede usar API de nivel alto o de nivel bajo para cargar objetos grandes. Estas API admiten los encabezados relacionados con el cifrado en la solicitud.
-
Cuando utiliza la API TransferManager
de alto nivel, usted proporciona los encabezados específicos del cifrado en la PutObjectRequest
(consulte Carga de un objeto con la carga multiparte).
-
Al usar la API de bajo nivel, proporcionará información relacionada con el cifrado en la InitiateMultipartUploadRequest
, seguida por información de cifrado idéntica en cada UploadPartRequest
. No necesita proporcionar encabezados específicos de cifrado en su CompleteMultipartUploadRequest
. Para ver ejemplos, consulte Uso de los AWS SDK (API de bajo nivel).
En el siguiente ejemplo se usa TransferManager
para crear objetos y se muestra cómo facilitar la información relacionada con SSE-C. En el ejemplo se realiza lo siguiente:
-
Crea un objeto mediante el método TransferManager.upload()
. En la instancia PutObjectRequest
, proporciona la información de la clave de cifrado para solicitar que Amazon S3 cifre el objeto utilizando la clave de facilitada por el cliente.
-
Realiza una copia del objeto llamando al método TransferManager.copy()
. El ejemplo indica a Amazon S3 que cifre la copia del objeto con una nueva SSECustomerKey
. Dado que el objeto de origen está cifrado con SSE-C, la CopyObjectRequest
también facilita la clave de cifrado del objeto de origen, de modo que Amazon S3 puede descifrar el objeto antes de copiarlo.
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 cargar objetos grandes, puede utilizar la API de carga multiparte (consulte Carga y copia de objetos con la carga multiparte).AWS SDK para .NET proporciona API de nivel alto o bajo para cargar objetos de gran tamaño. Estas API admiten los encabezados relacionados con el cifrado en la solicitud.
-
Cuando utiliza la API de Transfer-Utility
de alto nivel, usted proporciona los encabezados específicos del cifrado en TransferUtilityUploadRequest
como se muestra. Para ver ejemplos de código, consulte Carga de un objeto con la carga multiparte.
TransferUtilityUploadRequest request = new TransferUtilityUploadRequest()
{
FilePath = filePath,
BucketName = existingBucketName,
Key = keyName,
// Provide encryption information.
ServerSideEncryptionCustomerMethod = ServerSideEncryptionCustomerMethod.AES256,
ServerSideEncryptionCustomerProvidedKey = base64Key
,
};
-
Al usar la API de bajo nivel, proporcionará información relacionada con el cifrado en la solicitud de inicio de la carga multiparte, seguida por información de cifrado idéntica en las solicitudes de carga de partes subsiguientes. No necesita proporcionar encabezados específicos de cifrado en su solicitud de carga multiparte completa. Para ver ejemplos, consulte Uso de los AWS SDK (API de bajo nivel).
A continuación se muestra un ejemplo de carga multiparte de bajo nivel que hace una copia de un objeto grande existente. En el ejemplo, el objeto que se copiará se guarda en Amazon S3 mediante el SSE-C y usted también desea usar el SSE-C para guardar el objeto de destino. En el ejemplo, hará lo siguiente:
-
Inicie una solicitud de carga multiparte proporcionando una clave de cifrado y la información relacionada.
-
Proporcione las claves de cifrado del objeto de origen y de destino, y la información relacionada en CopyPartRequest
.
-
Recupere los metadatos del objeto para obtener el tamaño del objeto de origen que se copiará.
-
Cargue los objetos en 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);
}
}
}
}