

本文属于机器翻译版本。若本译文内容与英语原文存在差异，则一律以英文原文为准。

# 亚马逊 S3 加密客户端迁移（从 V1 到 V2）
<a name="s3-encryption-migration-v1-v2"></a>

**注意**  
如果您使用的是 Amazon S3 加密客户端的 V2，并且想要迁移到 V3，请参阅[亚马逊 S3 加密客户端迁移（V2 到 V3）](s3-encryption-migration-v2-v3.md)。

此主题介绍了如何将应用程序从 Amazon Simple Storage Service（Amazon S3）加密客户端的版本 1（V1）迁移到版本 2（V2），并确保应用程序在整个迁移过程中的可用性。

## 迁移概述
<a name="migration-overview-v1-v2"></a>

此迁移分为两个阶段：

1. **更新现有客户端以读取新格式。**首先，将 适用于 C\+\+ 的 AWS SDK 的已更新版本部署到应用程序中。这允许现有 V1 加密客户端解密由新的 V2 客户端写入的对象。如果您的应用程序使用多个 SDK AWS SDKs，则必须单独升级每个 SDK。

2. **将加密和解密客户端迁移到 V2。**一旦所有 V1 加密客户端都能读取新格式，就可以将现有加密和解密客户端迁移到各自的 V2 版本。

## 更新现有客户端以读取新格式
<a name="update-existing-clients-to-read-new-formats-v1-v2"></a>

您必须先将现有客户端更新到最新的 SDK 版本。完成此步骤后，您的应用程序的 V1 客户端将能够解密由 V2 加密客户端加密的对象，而无需更新应用程序的代码库。

### 生成并安装最新版本的 适用于 C\+\+ 的 AWS SDK
<a name="build-and-install-the-latest-version-of-the-sdk-cpp-v1-v2"></a>

 **从源代码使用 SDK 的应用程序** 

如果您 适用于 C\+\+ 的 AWS SDK 从源代码构建和安装，请从[`aws/aws-sdk-cpp`](https://github.com/aws/aws-sdk-cpp)上下载或克隆 SDK 源代码 GitHub。然后重复正常的构建和安装步骤。

如果您要 适用于 C\+\+ 的 AWS SDK 从 1.8.x 之前的版本升级，请参阅此[变更日志](https://github.com/aws/aws-sdk-cpp/blob/master/CHANGELOG.md)，了解每个主要版本中引入的重大更改。有关如何构建和安装的更多信息 适用于 C\+\+ 的 AWS SDK，请参阅[适用于 C\+\+ 的 AWS SDK 从源代码获取](sdk-from-source.md)。

 **从 Vcpkg 使用 SDK 的应用程序** 

如果您的应用程序使用 [Vcpkg](https://github.com/microsoft/vcpkg) 来跟踪 SDK 更新，只需使用现有的 Vcpkg 升级方法将 SDK 升级到最新版本即可。请记住，在版本发布和通过程序包管理器提供该版本之间会有延迟。最新版本始终可以通过[从源代码安装](sdk-from-source.md)获得。

您可以运行以下命令来升级程序包 `aws-sdk-cpp`：

```
vcpkg upgrade aws-sdk-cpp
```

并验证程序包 `aws-sdk-cpp` 的版本：

```
vcpkg list aws-sdk-cpp
```

版本应至少为 1.8.24。

有关将 Vcpkg 与配合使用的更多信息 适用于 C\+\+ 的 AWS SDK，请参阅。[适用于 C\+\+ 的 AWS SDK 从包管理器那里获取](sdk-from-pm.md)

### 构建、安装和部署您的应用程序
<a name="build-install-and-deploy-your-applications-v1-v2"></a>

如果您的应用程序静态链接到 适用于 C\+\+ 的 AWS SDK，则无需在应用程序中更改代码，但您必须重新构建应用程序才能使用最新的 SDK 更改。动态链接不需要完成此步骤。

升级应用程序的依赖版本并验证应用程序功能后，继续将应用程序部署到队列中。应用程序部署完成后，您可以继续下一阶段，迁移应用程序以使用 V2 加密和解密客户端。

## 将加密和解密客户端迁移到 V2
<a name="migrate-encryption-and-decryption-clients-to-v2-v1-v2"></a>

以下步骤展示了如何成功地将代码从 Amazon S3 加密客户端 V1 迁移到 V2。由于需要更改代码，因此无论应用程序是静态链接还是动态链接，您都需要重新构建应用程序。 适用于 C\+\+ 的 AWS SDK

### 使用新的加密材料
<a name="using-new-encryption-materials-v1-v2"></a>

使用 V2 Amazon S3 加密客户端和 V2 加密配置，以下加密材料已被弃用：
+  `SimpleEncryptionMaterials` 
+  `KMSEncryptionMaterials` 

它们已被以下安全加密材料所取代：
+  `SimpleEncryptionMaterialsWithGCMAAD` 
+  `KMSWithContextEncryptionMaterials` 

构建 V2 S3 加密客户端需要进行以下代码更改：
+   
**如果您在创建 S3 加密客户端时使用 `KMSEncryptionMaterials`：**  
  + 创建 V2 S3 加密客户端时，请将 `KMSEncryptionMaterials` 替换为 `KMSWithContextEncryptionMaterials` 并在 V2 加密配置中指定。
  + 使用 V2 Amazon S3 加密客户端放置对象时，必须明确提供字符串-字符串类型的上下文映射作为 KMS 上下文用于加密 CEK。这可能是一个空映射。
+   
**如果您在创建 S3 加密客户端时使用 `SimpleEncryptionMaterials`：**  
  + 创建 V2 Amazon S3 加密客户端时，请将 `SimpleEncryptionMaterials` 替换为 `SimpleEncryptionMaterialsWithGCMAAD` 并在 V2 加密配置中指定。
  + 使用 V2 Amazon S3 加密客户端放置对象时，必须明确提供空字符串-字符串类型的上下文映射，否则 SDK 将返回错误。

 **示例：使用 KMS/KMSWithContext 密钥封装算法** 

 *迁移前（KMS 密钥封装）* 

```
auto materials = Aws::MakeShared<KMSEncryptionMaterials>("s3Encryption", CUSTOMER_MASTER_KEY_ID);
CryptoConfiguration cryptoConfig;
S3EncryptionClient encryptionClient(materials, cryptoConfig);
// Code snippet here to setup the putObjectRequest object.
encryptionClient.PutObject(putObjectRequest);
```

 *迁移后（KMSWith上下文密钥换行）* 

```
auto materials = Aws::MakeShared<KMSWithContextEncryptionMaterials>("s3EncryptionV2", CUSTOMER_MASTER_KEY_ID);
CryptoConfigurationV2 cryptoConfig(materials);
S3EncryptionClientV2 encryptionClient(cryptoConfig);
// Code snippet here to setup the putObjectRequest object.
Aws::Map<Aws::String, Aws::String> kmsContextMap;
kmsContextMap.emplace("client", "aws-sdk-cpp");
kmsContextMap.emplace("version", "1.8.0");
encryptionClient.PutObject(putObjectRequest, kmsContextMap /* could be empty as well */);
```

 **示例：使用 AES/AES-GCM 密钥封装算法** 

 *迁移前（AES 密钥封装）* 

```
auto materials = Aws::MakeShared<SimpleEncryptionMaterials>("s3Encryption", HashingUtils::Base64Decode(AES_MASTER_KEY_BASE64));
CryptoConfiguration cryptoConfig;
S3EncryptionClient encryptionClient(materials, cryptoConfig);
// Code snippet here to setup the putObjectRequest object.
encryptionClient.PutObject(putObjectRequest);
```

 *迁移后（AES-GCM 密钥包装）* 

```
auto materials = Aws::MakeShared<SimpleEncryptionMaterialsWithGCMAAD>("s3EncryptionV2", HashingUtils::Base64Decode(AES_MASTER_KEY_BASE64));
CryptoConfigurationV2 cryptoConfig(materials);
S3EncryptionClientV2 encryptionClient(cryptoConfig);
// Code snippet here to setup the putObjectRequest object.
encryptionClient.PutObject(putObjectRequest, {} /* must be an empty map */);
```

## 其他示例
<a name="additional-examples-v1-v2"></a>

以下示例演示如何解决与从 V1 迁移到 V2 相关的特定用例。

### 解密由旧版 Amazon S3 加密客户端所加密的对象
<a name="decrypt-objects-encrypted-by-legacy-amazon-s3-encryption-clients-v1-v2"></a>

默认情况下，您无法使用 V2 Amazon S3 加密客户端来解密使用已弃用的密钥封装算法或已弃用的内容加密架构加密的对象。

以下密钥封装算法已被弃用：
+  `KMS` 
+  `AES_KEY_WRAP` 

以下内容加密架构已被弃用：
+  `CBC` 
+  `CTR` 

如果您在中使用传统的 Amazon S3 加密客户端 适用于 C\+\+ 的 AWS SDK 来加密对象，则在以下情况下，您可能会使用已弃用的方法：
+ 您用过 `SimpleEncryptionMaterials` 或 `KMSEncryptionMaterials`。
+ 您在加密配置中使用了 `ENCRYPTION_ONLY` 作为 `Crypto Mode`。

要使用 V2 Amazon S3 加密客户端解密由已弃用的密钥封装算法或已弃用的内容加密架构所加密的对象，您必须将 V2 加密配置中的 `SecurityProfile` 默认值从 `V2` 改为 `V2_AND_LEGACY`。

 **示例** 

 *迁移前* 

```
auto materials = Aws::MakeShared<KMSEncryptionMaterials>("s3Encryption", CUSTOMER_MASTER_KEY_ID);
CryptoConfiguration cryptoConfig;
S3EncryptionClient encryptionClient(materials, cryptoConfig);
// Code snippet here to setup the getObjectRequest object.
encryptionClient.GetObject(getObjectRequest);
```

 *迁移后* 

```
auto materials = Aws::MakeShared<KMSWithContextEncryptionMaterials>("s3EncryptionV2", CUSTOMER_MASTER_KEY_ID);
CryptoConfigurationV2 cryptoConfig(materials);
cryptoConfig.SetSecurityProfile(SecurityProfile::V2_AND_LEGACY);
S3EncryptionClientV2 encryptionClient(cryptoConfig);
// Code snippet here to setup the getObjectRequest object.
encryptionClient.GetObject(getObjectRequest);
```

### 使用范围解密对象
<a name="decrypt-objects-with-range-v1-v2"></a>

使用传统的 Amazon S3 加密客户端，您可以指定解密 S3 对象时要接收的字节范围。在 V2 Amazon S3 加密客户端中，此功能默认为 `DISABLED` 状态。因此，您必须将 V2 加密配置中 `RangeGetMode` 的默认值从 `DISABLED` 改为 `ALL`。

 **示例** 

 *迁移前* 

```
auto materials = Aws::MakeShared<KMSEncryptionMaterials>("s3Encryption", CUSTOMER_MASTER_KEY_ID);
CryptoConfiguration cryptoConfig;
S3EncryptionClient encryptionClient(materials, cryptoConfig);
// Code snippet here to setup the getObjectRequest object.
getObjectRequest.WithRange("bytes=38-75");
encryptionClient.GetObject(getObjectRequest);
```

 *迁移后* 

```
auto materials = Aws::MakeShared<KMSWithContextEncryptionMaterials>("s3EncryptionV2", CUSTOMER_MASTER_KEY_ID);
CryptoConfigurationV2 cryptoConfig(materials);
cryptoConfig.SetUnAuthenticatedRangeGet(RangeGetMode::ALL);
S3EncryptionClientV2 encryptionClient(cryptoConfig);
// Code snippet here to setup the getObjectRequest object.
getObjectRequest.WithRange("bytes=38-75");
encryptionClient.GetObject(getObjectRequest);
```

### 使用任意 CMK 解密对象
<a name="decrypt-objects-with-any-cmk-v1-v2"></a>

在解密使用 `KMSWithContextEncryptionMaterials` 加密的对象时，V2 Amazon S3 加密客户端能够通过提供空的主密钥让 KMS 找到正确的 CMK。此功能默认为 `DISABLED`。您必须通过对 KMS 加密材料调用 `SetKMSDecryptWithAnyCMK(true)` 来明确配置该功能。

 **示例** 

 *迁移前* 

```
auto materials = Aws::MakeShared<KMSEncryptionMaterials>("s3Encryption", ""/* provide an empty KMS Master Key*/);
CryptoConfiguration cryptoConfig;
S3EncryptionClient encryptionClient(materials, cryptoConfig);
// Code snippet here to setup the getObjectRequest object.
encryptionClient.GetObject(getObjectRequest);
```

 *迁移后* 

```
auto materials = Aws::MakeShared<KMSWithContextEncryptionMaterials>("s3EncryptionV2", ""/* provide an empty KMS Master Key*/);
materials.SetKMSDecryptWithAnyCMK(true);
CryptoConfigurationV2 cryptoConfig(materials);
S3EncryptionClientV2 encryptionClient(cryptoConfig);
// Code snippet here to setup the getObjectRequest object.
encryptionClient.GetObject(getObjectRequest);
```

有关所有这些迁移场景的完整代码，请参阅 Github 上的 [Amazon S3 加密示例](https://github.com/awsdocs/aws-doc-sdk-examples/tree/main/cpp/example_code/s3encryption)。