Amazon Simple Storage Service
开发人员指南 (API Version 2006-03-01)
AWS 服务或AWS文档中描述的功能,可能因地区/位置而异。点 击 Getting Started with Amazon AWS to see specific differences applicable to the China (Beijing) Region.

使用 AWS Java 开发工具包指定具有客户提供的加密密钥的服务器端加密

以下 Java 代码示例演示了使用客户提供的密钥的服务器端加密 (SSE-C) (请参阅通过使用客户提供的加密密钥的服务器端加密 (SSE-C) 保护数据)。本示例执行以下操作;每个操作都显示您如何在请求中指定 SSE-C 相关标头:

  • 放置对象 – 上传对象,该对象请求使用客户提供的加密密钥的服务器端加密。

  • 获取对象 – 下载您在前面的步骤中上传的对象。本示例显示您在 Get 请求中提供的加密信息必须与您在上传对象时提供的信息相同,以便 Amazon S3 在返回该对象之前可以将其解密。

  • 获取对象元数据 – 该请求表明,必须提供您在创建对象时指定的相同加密信息才能检索对象的元数据。

  • 复制对象 – 本示例复制之前上传的对象。因为源对象是使用 SSE-C 存储的,因此在复制请求中必须提供加密信息。默认情况下,对象副本不会加密。但是在本示例中,您请求 Amazon S3 存储使用 SSE-C 加密的对象副本,因此还必须提供目标的 SSE-C 加密信息。

注意

本示例显示如何在单个操作中上传对象。如下例所示,在使用分段上传 API 上传大型对象时,需要提供您在请求中提供的相同加密信息。有关分段上传的 AWS SDK for Java 示例,请参阅使用适用于分段上传的 AWS Java 开发工具包 (高级别 API) 使用适用于分段上传的 AWS Java 开发工具包 (低级别 API)

适用于 Java 的 AWS 开发工具包提供了 SSECustomerKey 类,以便您在请求中添加必需的加密信息 (请参阅使用 SSE-C)。您只需要提供加密密钥。Java 开发工具包设置加密密钥和算法的 MD5 摘要值。

有关如何创建和测试有效示例的信息,请参阅 测试 Java 代码示例

Copy
import java.io.BufferedReader; import java.io.File; import java.io.IOException; import java.io.InputStreamReader; import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; import javax.crypto.KeyGenerator; import javax.crypto.SecretKey; import com.amazonaws.AmazonClientException; import com.amazonaws.AmazonServiceException; import com.amazonaws.auth.profile.ProfileCredentialsProvider; import com.amazonaws.services.s3.AmazonS3; import com.amazonaws.services.s3.AmazonS3Client; import com.amazonaws.services.s3.model.CopyObjectRequest; import com.amazonaws.services.s3.model.GetObjectMetadataRequest; import com.amazonaws.services.s3.model.GetObjectRequest; import com.amazonaws.services.s3.model.ObjectMetadata; import com.amazonaws.services.s3.model.PutObjectRequest; import com.amazonaws.services.s3.model.S3Object; import com.amazonaws.services.s3.model.S3ObjectInputStream; import com.amazonaws.services.s3.model.SSECustomerKey; public class ServerSideEncryptionUsingClientSideEncryptionKey { private static String bucketName = "*** Provide bucket name ***"; private static String keyName = "*** Provide key ***"; private static String uploadFileName = "*** Provide file name ***"; private static String targetKeyName = "*** provide target key ***"; private static AmazonS3 s3client; public static void main(String[] args) throws IOException, NoSuchAlgorithmException { s3client = new AmazonS3Client(new ProfileCredentialsProvider()); try { System.out.println("Uploading a new object to S3 from a file\n"); File file = new File(uploadFileName); // Create encryption key. SecretKey secretKey = generateSecretKey(); SSECustomerKey sseKey = new SSECustomerKey(secretKey); // 1. Upload object. uploadObject(file, sseKey); // 2. Download object. downloadObject(sseKey); // 3. Get object metadata (and verify AES256 encryption). retrieveObjectMetadata(sseKey); // 4. Copy object (both source and object use SSE-C). copyObject(sseKey); } catch (AmazonServiceException ase) { System.out.println("Caught an AmazonServiceException, which " + "means your request made it " + "to Amazon S3, but was rejected with an error response" + " for some reason."); System.out.println("Error Message: " + ase.getMessage()); System.out.println("HTTP Status Code: " + ase.getStatusCode()); System.out.println("AWS Error Code: " + ase.getErrorCode()); System.out.println("Error Type: " + ase.getErrorType()); System.out.println("Request ID: " + ase.getRequestId()); } catch (AmazonClientException ace) { System.out.println("Caught an AmazonClientException, which " + "means the client encountered " + "an internal error while trying to " + "communicate with S3, " + "such as not being able to access the network."); System.out.println("Error Message: " + ace.getMessage()); } } private static void copyObject(SSECustomerKey sseKey) { // Create new encryption key for target so it is saved using sse-c SecretKey secretKey2 = generateSecretKey(); SSECustomerKey newSseKey = new SSECustomerKey(secretKey2); CopyObjectRequest copyRequest = new CopyObjectRequest(bucketName, keyName, bucketName, targetKeyName) .withSourceSSECustomerKey(sseKey) .withDestinationSSECustomerKey(newSseKey); s3client.copyObject(copyRequest); System.out.println("Object copied"); } private static void retrieveObjectMetadata(SSECustomerKey sseKey) { GetObjectMetadataRequest getMetadataRequest = new GetObjectMetadataRequest(bucketName, keyName) .withSSECustomerKey(sseKey); ObjectMetadata objectMetadata = s3client.getObjectMetadata(getMetadataRequest); System.out.println("object size " + objectMetadata.getContentLength()); System.out.println("Metadata retrieved"); } private static PutObjectRequest uploadObject(File file, SSECustomerKey sseKey) { // 1. Upload Object. PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, keyName, file) .withSSECustomerKey(sseKey); s3client.putObject(putObjectRequest); System.out.println("Object uploaded"); return putObjectRequest; } private static void downloadObject(SSECustomerKey sseKey) throws IOException { // Get a range of bytes from an object. GetObjectRequest getObjectRequest = new GetObjectRequest(bucketName, keyName) .withSSECustomerKey(sseKey); S3Object s3Object = s3client.getObject(getObjectRequest); System.out.println("Printing bytes retrieved."); displayTextInputStream(s3Object.getObjectContent()); } private static void displayTextInputStream(S3ObjectInputStream input) throws IOException { // Read one text line at a time and display. BufferedReader reader = new BufferedReader(new InputStreamReader(input)); while (true) { String line = reader.readLine(); if (line == null) break; System.out.println(" " + line); } System.out.println(); } private static SecretKey generateSecretKey() { try { KeyGenerator generator = KeyGenerator.getInstance("AES"); generator.init(256, new SecureRandom()); return generator.generateKey(); } catch (Exception e) { e.printStackTrace(); System.exit(-1); return null; } } }

其他 Amazon S3 操作和 SSE-C

上一部分中的示例显示了如何在 PUT、GET、Head 和 Copy 操作中请求使用客户提供的密钥的服务器端加密 (SSE-C)。这一部分介绍支持 SSE-C 的其他 API。

要上传大型对象,您可以使用分段上传 API (请参阅使用分段上传 API 上传对象)。可以使用高级或低级 API 上传大型对象。这些 API 支持在请求中使用与加密相关的标头。

  • 当使用高级 Transfer-Utility API 时,可以在 TransferManager 中提供加密特定的标头 (请参阅使用适用于分段上传的 AWS Java 开发工具包 (高级别 API) )。

  • 当使用低级 API 时,可以在启动分段上传请求中提供加密相关的信息,并在后续的分段上传请求中提供相同加密信息。您不需要在完成的分段上传请求中提供任何加密特定的标头。有关示例,请参阅 使用适用于分段上传的 AWS Java 开发工具包 (低级别 API)

    以下示例使用 TransferManager 创建对象并显示如何提供 SSE-C 相关信息。本示例执行以下操作:

    • 使用 TransferManager.upload 方法创建对象。在 PutObjectRequest 实例中,提供加密密钥信息以请求 Amazon S3 存储使用客户提供的加密密钥加密的对象。

    • 通过调用 TransferManager.copy 方法复制对象。在 CopyObjectRequest 中,本示例请求 Amazon S3 存储同样使用客户提供的加密密钥加密的对象副本。因为源对象是使用 SSE-C 加密的,因此 CopyObjectRequest 还提供源对象的加密密钥,以便 Amazon S3 可以在复制之前解密对象。

    Copy
    import java.io.File; import java.security.SecureRandom; import javax.crypto.KeyGenerator; import javax.crypto.SecretKey; import com.amazonaws.AmazonClientException; import com.amazonaws.auth.profile.ProfileCredentialsProvider; 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.Upload; public class ServerSideEncryptionCopyObjectUsingHLwithSSEC { public static void main(String[] args) throws Exception { String existingBucketName = "*** Provide existing bucket name ***"; String fileToUpload = "*** file path ***"; String keyName = "*** New object key ***"; String targetKeyName = "*** Key name for object copy ***"; TransferManager tm = new TransferManager(new ProfileCredentialsProvider()); // 1. first create an object from a file. PutObjectRequest putObjectRequest = new PutObjectRequest(existingBucketName, keyName, new File(fileToUpload)); // we want object stored using SSE-C. So we create encryption key. SecretKey secretKey1 = generateSecretKey(); SSECustomerKey sseCustomerEncryptionKey1 = new SSECustomerKey(secretKey1); putObjectRequest.setSSECustomerKey(sseCustomerEncryptionKey1); // now create object. //Upload upload = tm.upload(existingBucketName, keyName, new File(sourceFile)); Upload upload = tm.upload(putObjectRequest); try { // Or you can block and wait for the upload to finish upload.waitForCompletion(); //tm.getAmazonS3Client().putObject(putObjectRequest); System.out.println("Object created."); } catch (AmazonClientException amazonClientException) { System.out.println("Unable to upload file, upload was aborted."); amazonClientException.printStackTrace(); } // 2. Now make object copy (in the same bucket). Store target using sse-c. CopyObjectRequest copyObjectRequest = new CopyObjectRequest(existingBucketName, keyName, existingBucketName, targetKeyName); SecretKey secretKey2 = generateSecretKey(); SSECustomerKey sseTargetObjectEncryptionKey = new SSECustomerKey(secretKey2); copyObjectRequest.setSourceSSECustomerKey(sseCustomerEncryptionKey1); copyObjectRequest.setDestinationSSECustomerKey(sseTargetObjectEncryptionKey); // TransferManager processes all transfers asynchronously, // so this call will return immediately. Copy copy = tm.copy(copyObjectRequest); try { // Or you can block and wait for the upload to finish copy.waitForCompletion(); System.out.println("Copy complete."); } catch (AmazonClientException amazonClientException) { System.out.println("Unable to upload file, upload was aborted."); amazonClientException.printStackTrace(); } } private static SecretKey generateSecretKey() { KeyGenerator generator; try { generator = KeyGenerator.getInstance("AES"); generator.init(256, new SecureRandom()); return generator.generateKey(); } catch (Exception e) { e.printStackTrace(); System.exit(-1); return null; } } }