

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

# 适用于 PHP 的 AWS SDK 版本 3 中的 Amazon S3 客户端加密
<a name="s3-encryption-client"></a>

使用客户端加密，数据可在您的环境中直接加密和解密。这就意味着，数据在传输到 Amazon S3 之前已加密，您无需使用外部服务来处理加密。对于新的实现，我们建议使用`S3EncryptionClientV3`和`S3EncryptionMultipartUploaderV3`而不是和`S3EncryptionClientV2`以及`S3EncryptionMultipartUploaderV2`已弃用的`S3EncryptionClient`和。`S3EncryptionMultipartUploader`建议仍在使用已弃用版本的旧实现尝试迁移。`S3EncryptionClientV3` 继续支持对使用旧版 `S3EncryptionClient` 加密的数据进行解密。

 适用于 PHP 的 AWS SDK 实现了[信封加密](https://docs.aws.amazon.com/kms/latest/developerguide/workflow.html)，并使用 [OpenSSL](https://www.openssl.org/) 进行加密和解密。该实现可[与其他与其功能支持相匹配 SDKs 的](https://docs.aws.amazon.com/general/latest/gr/aws_sdk_cryptography.html)实现互操作。它还与[开发工具包基于 Promise 的异步工作流程](guide_promises.md)相兼容。

## 迁移指南
<a name="migration-guide"></a>

[对于那些试图从已弃用的客户端迁移到新客户端的用户，[这里](https://docs.aws.amazon.com/sdk-for-php/v3/developer-guide/s3-encryption-migration-v1-v2-section.html)有从 v1 迁移到 v2 的迁移指南，此处有从 v2 迁移到 v3 的迁移指南。](https://docs.aws.amazon.com/sdk-for-php/v3/developer-guide/s3-encryption-migration-v2-v3-section.html)

## 设置
<a name="setup"></a>

要开始使用客户端加密，您需要：
+ [AWS KMS 加密密钥](https://docs.aws.amazon.com/kms/latest/developerguide/create-keys.html) 
+ 一个 [S3 存储桶](https://docs.aws.amazon.com/AmazonS3/latest/gsg/CreatingABucket.html) 

在运行任何示例代码之前，请配置您的 AWS 证书。参见[适用于 PHP 的 AWS SDK 版本 3 的凭证](guide_credentials.md)。

## 加密
<a name="encryption"></a>

上传加密对象除了标准参数之外还`S3EncryptionClientV3`需要四个额外的`PutObject`参数：
+  `'@KmsEncryptionContext'` 是一个密钥值对，可用于为加密对象添加额外的安全层。加密客户端必须传入相同密钥，这将在 get 调用时自动进行。如果不需要其他上下文，请传入空数组。
+  `@CipherOptions` 是加密的其他配置，包括要使用的密码和密钥大小。
+  `@MaterialsProvider` 是一个提供程序，用于处理生成密码密钥和初始化向量，以及加密密码密钥。
+  `@CommitmentPolicy`是一种策略选项，它规定了如何使用密钥承诺或不使用密钥承诺来读取对象，以及如何使用密钥承诺或不使用密钥承诺来编写对象。

```
use Aws\S3\S3Client;
use Aws\S3\Crypto\S3EncryptionClientV3;
use Aws\Kms\KmsClient;
use Aws\Crypto\KmsMaterialsProviderV3;

 // Let's construct our S3EncryptionClient using an S3Client
 $encryptionClient = new S3EncryptionClientV3(
     new S3Client([
         'profile' => 'default',
         'region' => 'us-east-1',
         'version' => 'latest',
     ])
 );

 $kmsKeyId = 'kms-key-id';
 $materialsProvider = new KmsMaterialsProviderV3(
     new KmsClient([
         'profile' => 'default',
         'region' => 'us-east-1',
         'version' => 'latest',
     ]),
     $kmsKeyId
 );

 $bucket = 'the-bucket-name';
 $key = 'the-file-name';
 $cipherOptions = [
     'Cipher' => 'gcm',
     'KeySize' => 256,
     // Additional configuration options
 ];

 $result = $encryptionClient->putObject([
     '@MaterialsProvider' => $materialsProvider,
     '@CipherOptions' => $cipherOptions,
     '@CommitmentPolicy' => 'REQUIRE_ENCRYPT_REQUIRE_DECRYPT',
     '@KmsEncryptionContext' => ['context-key' => 'context-value'],
     'Bucket' => $bucket,
     'Key' => $key,
     'Body' => fopen('file-to-encrypt.txt', 'r'),
 ]);
```

**注意**  
除了基于 Amazon S3 和 AWS KMS基于 Amazon S3 的服务错误外，如果配置不`'@CipherOptions'`正确，您可能会收到抛出的`InvalidArgumentException`对象。

## 解密
<a name="decryption"></a>

下载和解密对象除了标准`GetObject`参数外，还有五个额外的参数，其中两个是必需的。客户端将为您检测基本的密码选项。
+   
** `'@SecurityProfile'`: 如果设置为 “V3”，则仅在兼容 v3 的情况下加密的对象**  
的对象。将此参数设置为 “V3\$1AND\$1LEGACY” 还允许解密以 V1 兼容格式加密的对象。要支持迁移，请将 @ 设置为 “V3\$1AND SecurityProfile \$1LEGACY”。仅在开发新应用程序时使用 “V3”。
+   
** `'@MaterialsProvider'` 是一个提供程序，用于处理生成密码密钥和初始化向量，**  
以及加密密码密钥。
+   
** `'@KmsAllowDecryptWithAnyCmk'`：（可选）将此参数设置为 True 即可启用解密，**  
无需向的构造函数提供 KMS 密钥 ID MaterialsProvider。默认值为 False。
+   
** `'@CipherOptions'`（可选）是加密的其他配置，包括**  
要使用的密码和密钥大小。
+   
** `@CommitmentPolicy`policy 选项，它规定了如何使用任一方法读取对象 **  
关键承诺或不带关键承诺，以及如何用关键承诺或不带关键承诺来撰写对象。

```
$result = $encryptionClient->getObject([
    '@KmsAllowDecryptWithAnyCmk' => true,
    '@SecurityProfile' => 'V2_AND_LEGACY',
    '@CommitmentPolicy' => 'REQUIRE_ENCRYPT_ALLOW_DECRYPT',
    '@MaterialsProvider' => $materialsProvider,
    '@CipherOptions' => $cipherOptions,
    'Bucket' => $bucket,
    'Key' => $key,
]);
```

**注意**  
除了基于 Amazon S3 和 AWS KMS基于 Amazon S3 的服务错误外，如果配置不`'@CipherOptions'`正确，您可能会收到抛出的`InvalidArgumentException`对象。

## 密码配置
<a name="cipher-configuration"></a>

** `'Cipher'`（字符串）**  
加密客户端在加密时使用的密码方法。此时只支持“gcm”。

**重要**  
PHP 通过[版本 7.1 的更新](http://php.net/manual/en/migration71.new-features.php)包含了额外的参数，在使用 OpenSSL 进行 GCM 加密时，这些参数对于[加密](http://php.net/manual/en/function.openssl-encrypt.php)和[解密](http://php.net/manual/en/function.openssl-decrypt.php)是必要的。对于 PHP 7.0 及更早版本，加密客户端 `S3EncryptionClientV2` 和 `S3EncryptionMultipartUploaderV2` 提供并使用支持 GCM 的填充代码。但是，使用填充代码来处理大型输入的性能会比使用 PHP 7.1\$1 的本机实现时慢得多，因此可能需要升级较旧的 PHP 版本环境才能有效使用它们。

** `'KeySize'` (int)**  
生成的用于加密的内容加密密钥的长度。默认为 256 位。有效的配置选项为 256 位。

** `'Aad'`（字符串）**  
可添加到加密负载中的可选“附加身份验证数据”。在解密时将验证此信息。`Aad` 仅在使用“gcm”密码时才可用。

**重要**  
并非所有人都支持其他身份验证数据 AWS SDKs ，因此其他人 SDKs 可能无法解密使用此参数加密的文件。

## 元数据策略
<a name="metadata-strategies"></a>

您还可以选择提供实施 `Aws\Crypto\MetadataStrategyInterface` 的类的实例。这个简单的接口可保存和加载 `Aws\Crypto\MetadataEnvelope`，其中包含您的信封加密材料。开发工具包提供两个类来实施此功能：`Aws\S3\Crypto\HeadersMetadataStrategy` 和 `Aws\S3\Crypto\InstructionFileMetadataStrategy`。默认情况下使用 `HeadersMetadataStrategy`。

```
$strategy = new InstructionFileMetadataStrategy(
    $s3Client
);

$encryptionClient->putObject([
    '@MaterialsProvider' => $materialsProvider,
    '@MetadataStrategy' => $strategy,
    '@CommitmentPolicy' => 'REQUIRE_ENCRYPT_REQUIRE_DECRYPT',
    '@KmsEncryptionContext' => [],
    '@CipherOptions' => $cipherOptions,
    'Bucket' => $bucket,
    'Key' => $key,
    'Body' => fopen('file-to-encrypt.txt', 'r'),
]);

$result = $encryptionClient->getObject([
    '@KmsAllowDecryptWithAnyCmk' => false,
    '@MaterialsProvider' => $materialsProvider,
    '@SecurityProfile' => 'V3',
    '@CommitmentPolicy' => 'REQUIRE_ENCRYPT_REQUIRE_DECRYPT',
    '@MetadataStrategy' => $strategy,
    '@CipherOptions' => $cipherOptions,
    'Bucket' => $bucket,
    'Key' => $key,
]);
```

调用 `HeadersMetadataStrategy`::class`InstructionFileMetadataStrategy` 也可提供 * 和 * 的类名常量。

```
$result = $encryptionClient->putObject([
    '@MaterialsProvider' => $materialsProvider,
    '@CommitmentPolicy' => 'REQUIRE_ENCRYPT_REQUIRE_DECRYPT',
    '@MetadataStrategy' => HeadersMetadataStrategy::class,
    '@CipherOptions' => $cipherOptions,
    'Bucket' => $bucket,
    'Key' => $key,
    'Body' => fopen('file-to-encrypt.txt', 'r'),
]);
```

**注意**  
如果构造文件上传后发生错误，不会自动删除该文件。

## 分段上传
<a name="multipart-uploads"></a>

也可以利用客户端加密执行分段上传。`Aws\S3\Crypto\S3EncryptionMultipartUploaderV3` 会在上传之前准备用于加密的源流。使用 `Aws\S3\MultipartUploader` 和 `Aws\S3\Crypto\S3EncryptionClientV3` 创建的过程也与此类似。`S3EncryptionMultipartUploaderV3` 能以与 `'@MetadataStrategy'` 相同的方式处理 `S3EncryptionClientV3` 选项，以及所有可用的 `'@CipherOptions'` 配置。

```
$kmsKeyId = 'kms-key-id';
$materialsProvider = new KmsMaterialsProviderV3(
    new KmsClient([
        'region' => 'us-east-1',
        'version' => 'latest',
        'profile' => 'default',
    ]),
    $kmsKeyId
);

$bucket = 'the-bucket-name';
$key = 'the-upload-key';
$cipherOptions = [
    'Cipher' => 'gcm'
    'KeySize' => 256,
    // Additional configuration options
];

$multipartUploader = new S3EncryptionMultipartUploaderV3(
    new S3Client([
        'region' => 'us-east-1',
        'version' => 'latest',
        'profile' => 'default',
    ]),
    fopen('large-file-to-encrypt.txt', 'r'),
    [
        '@MaterialsProvider' => $materialsProvider,
        '@CipherOptions' => $cipherOptions,
        '@CommitmentPolicy' => 'REQUIRE_ENCRYPT_REQUIRE_DECRYPT',
        'bucket' => $bucket,
        'key' => $key,
    ]
);
$multipartUploader->upload();
```

**注意**  
除了基于 Amazon S3 和 AWS KMS基于 Amazon S3 的服务错误外，如果配置不`'@CipherOptions'`正确，您可能会收到抛出的`InvalidArgumentException`对象。