

本文為英文版的機器翻譯版本，如內容有任何歧義或不一致之處，概以英文版為準。

# 適用於 Python 的 AWS Encryption SDK
<a name="python"></a>

本主題說明如何安裝及使用 適用於 Python 的 AWS Encryption SDK。如需使用 進行程式設計的詳細資訊 適用於 Python 的 AWS Encryption SDK，請參閱 GitHub 上的 [aws-encryption-sdk-python](https://github.com/aws/aws-encryption-sdk-python/) 儲存庫。如需 API 文件，請參閱[閱讀相關文件](https://aws-encryption-sdk-python.readthedocs.io/en/latest/)。

**Topics**
+ [

## 先決條件
](#python-prerequisites)
+ [

## 安裝
](#python-installation)
+ [範例](python-example-code.md)

## 先決條件
<a name="python-prerequisites"></a>

安裝 之前 適用於 Python 的 AWS Encryption SDK，請確定您有下列先決條件。

**支援的 Python 版本**  
3.2.0 版和更新 適用於 Python 的 AWS Encryption SDK 版本需要 Python 3.8 或更新版本。  
[AWS 密碼編譯材料提供者程式庫](https://github.com/aws/aws-cryptographic-material-providers-library) (MPL) 是 4.*x* 版中 適用於 Python 的 AWS Encryption SDK 引入之 的選用相依性。如果您想要安裝 MPL，則必須使用 Python 3.11 或更新版本。
舊版 AWS Encryption SDK 支援 Python 2.7 和 Python 3.4 及更新版本，但建議您使用最新版本的 AWS Encryption SDK。  
若要下載 Python，請參閱 [Python 下載](https://www.python.org/downloads/)。

**適用於 Python 的 pip 安裝工具**  
`pip` 包含在 Python 3.6 和更新版本中，但您可能想要升級。如需升級或安裝 的詳細資訊`pip`，請參閱 `pip` 文件中的[安裝](https://pip.pypa.io/en/latest/installation/)。

## 安裝
<a name="python-installation"></a>

安裝最新版本的 適用於 Python 的 AWS Encryption SDK。

**注意**  
所有 適用於 Python 的 AWS Encryption SDK 早於 3.0.0 的 版本都處於[end-of-support階段](https://docs.aws.amazon.com/sdkref/latest/guide/maint-policy.html#version-life-cycle)。  
您可以從 2.0.*x* 版和更新版本安全地更新至最新版本的 ， AWS Encryption SDK 而不需要變更任何程式碼或資料。不過，2.0.*x* 版中引進[的新安全功能](about-versions.md#version-2)無法回溯相容。若要從 1.7.*x* 之前的版本更新至 2.0.*x* 及更新版本，您必須先更新至最新的 1 AWS Encryption SDK.*x* 版本。如需詳細資訊，請參閱[遷移您的 AWS Encryption SDK](migration.md)。

使用 `pip` 安裝 適用於 Python 的 AWS Encryption SDK，如下列範例所示。

**若要安裝最新版本**  

```
pip install "aws-encryption-sdk[MPL]"
```
`[MPL]` 尾碼會安裝[AWS 密碼編譯物料提供者程式庫 ](https://github.com/aws/aws-cryptographic-material-providers-library)(MPL)。MPL 包含用於加密和解密資料的建構。MPL 是 4.*x* 版中 適用於 Python 的 AWS Encryption SDK 引入之 的選用相依性。我們強烈建議您安裝 MPL。不過，如果您不打算使用 MPL，您可以省略`[MPL]`尾碼。

如需使用 pip 來安裝及升級套件的詳細資訊，請參閱[安裝套件](https://packaging.python.org/tutorials/installing-packages/)。

在所有平台上 適用於 Python 的 AWS Encryption SDK 都需要[密碼編譯程式庫](https://cryptography.io/en/latest/) (pyca/cryptography)。所有版本的 `pip`會自動在 Windows 上安裝和建置程式`cryptography`庫。 `pip` 8.1 和更新版本會自動在 Linux `cryptography`上安裝和建置 。如果您使用的是舊版 ，`pip`而且 Linux 環境沒有建置程式`cryptography`庫所需的工具，則需要安裝它們。如需詳細資訊，請參閱[在 Linux 上建置密碼編譯](https://cryptography.io/en/latest/installation.html#building-cryptography-on-linux)。

密碼[編譯](https://cryptography.io/en/latest/)相依性介於 2.5.0 和 3.3.2 之間的 適用於 Python 的 AWS Encryption SDK PIN 版本 1.10.0 和 2.5.0。其他版本的 適用於 Python 的 AWS Encryption SDK 安裝最新版本的密碼編譯。如果您需要 3.3.2 之後的加密版本，建議您使用最新的 主要版本。 適用於 Python 的 AWS Encryption SDK

如需 的最新開發版本 適用於 Python 的 AWS Encryption SDK，請前往 GitHub 中的 [aws-encryption-sdk-python](https://github.com/aws/aws-encryption-sdk-python/) 儲存庫。

安裝 之後 適用於 Python 的 AWS Encryption SDK，請先查看本指南中的 [Python 範例程式碼](python-example-code.md)。

# 適用於 Python 的 AWS Encryption SDK 範例程式碼
<a name="python-example-code"></a>

下列範例示範如何使用 適用於 Python 的 AWS Encryption SDK 來加密和解密資料。

本節中的範例示範如何使用 4.*x* 版 適用於 Python 的 AWS Encryption SDK 搭配選用[的密碼編譯材料提供者程式庫](https://github.com/aws/aws-cryptographic-material-providers-library)相依性 (`aws-cryptographic-material-providers`)。若要檢視使用舊版或沒有材料提供者程式庫 (MPL) 的安裝範例，請在 GitHub 上 [aws-encryption-sdk-python](https://github.com/aws/aws-encryption-sdk-python/) 儲存庫[的版本](https://github.com/aws/aws-encryption-sdk-python/releases)清單中尋找您的版本。

當您 適用於 Python 的 AWS Encryption SDK 搭配 MPL 使用 4.*x* 版時，它會使用 [keyring ](choose-keyring.md)來執行[信封加密](concepts.md#envelope-encryption)。 AWS Encryption SDK 提供與您在先前版本中使用的主金鑰提供者相容的 keyring。如需詳細資訊，請參閱[Keyring 相容性](choose-keyring.md#keyring-compatibility)。如需從主金鑰提供者遷移至 keyring 的範例，請參閱 GitHub 上儲存`aws-encryption-sdk-python`庫中的[遷移範例](https://github.com/aws/aws-encryption-sdk-python/tree/master/examples/src/migration)；

**Topics**
+ [Strings](#python-example-strings)
+ [位元組串流](#python-example-streams)

## 加密和解密字串
<a name="python-example-strings"></a>

下列範例示範如何使用 AWS Encryption SDK 來加密和解密字串。此範例使用具有對稱加密 KMS 金鑰的 [AWS KMS keyring](use-kms-keyring.md)。

此範例會使用[預設承諾政策](migrate-commitment-policy.md) 來執行個體化 AWS Encryption SDK 用戶端`REQUIRE_ENCRYPT_REQUIRE_DECRYPT`。如需詳細資訊，請參閱[設定您的承諾政策](migrate-commitment-policy.md)。

```
# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0
"""
This example sets up the KMS Keyring

The AWS KMS keyring uses symmetric encryption KMS keys to generate, encrypt and
decrypt data keys. This example creates a KMS Keyring and then encrypts a custom input EXAMPLE_DATA
with an encryption context. This example also includes some sanity checks for demonstration:
1. Ciphertext and plaintext data are not the same
2. Encryption context is correct in the decrypted message header
3. Decrypted plaintext value matches EXAMPLE_DATA
These sanity checks are for demonstration in the example only. You do not need these in your code.

AWS KMS keyrings can be used independently or in a multi-keyring with other keyrings
of the same or a different type.

"""

import boto3
from aws_cryptographic_material_providers.mpl import AwsCryptographicMaterialProviders
from aws_cryptographic_material_providers.mpl.config import MaterialProvidersConfig
from aws_cryptographic_material_providers.mpl.models import CreateAwsKmsKeyringInput
from aws_cryptographic_material_providers.mpl.references import IKeyring
from typing import Dict  # noqa pylint: disable=wrong-import-order

import aws_encryption_sdk
from aws_encryption_sdk import CommitmentPolicy

EXAMPLE_DATA: bytes = b"Hello World"


def encrypt_and_decrypt_with_keyring(
    kms_key_id: str
):
    """Demonstrate an encrypt/decrypt cycle using an AWS KMS keyring.

    Usage: encrypt_and_decrypt_with_keyring(kms_key_id)
    :param kms_key_id: KMS Key identifier for the KMS key you want to use for encryption and
    decryption of your data keys.
    :type kms_key_id: string
    
    """
    # 1. Instantiate the encryption SDK client.
    # This builds the client with the REQUIRE_ENCRYPT_REQUIRE_DECRYPT commitment policy,
    # which enforces that this client only encrypts using committing algorithm suites and enforces
    # that this client will only decrypt encrypted messages that were created with a committing
    # algorithm suite.
    # This is the default commitment policy if you were to build the client as
    # `client = aws_encryption_sdk.EncryptionSDKClient()`.
    client = aws_encryption_sdk.EncryptionSDKClient(
        commitment_policy=CommitmentPolicy.REQUIRE_ENCRYPT_REQUIRE_DECRYPT
    )

    # 2. Create a boto3 client for KMS.
    kms_client = boto3.client('kms', region_name="us-west-2")

    # 3. Optional: create encryption context.
    # Remember that your encryption context is NOT SECRET.
    encryption_context: Dict[str, str] = {
        "encryption": "context",
        "is not": "secret",
        "but adds": "useful metadata",
        "that can help you": "be confident that",
        "the data you are handling": "is what you think it is",
    }

    # 4. Create your keyring
    mat_prov: AwsCryptographicMaterialProviders = AwsCryptographicMaterialProviders(
        config=MaterialProvidersConfig()
    )

    keyring_input: CreateAwsKmsKeyringInput = CreateAwsKmsKeyringInput(
        kms_key_id=kms_key_id,
        kms_client=kms_client
    )

    kms_keyring: IKeyring = mat_prov.create_aws_kms_keyring(
        input=keyring_input
    )

    # 5. Encrypt the data with the encryptionContext.
    ciphertext, _ = client.encrypt(
        source=EXAMPLE_DATA,
        keyring=kms_keyring,
        encryption_context=encryption_context
    )

    # 6. Demonstrate that the ciphertext and plaintext are different.
    # (This is an example for demonstration; you do not need to do this in your own code.)
    assert ciphertext != EXAMPLE_DATA, \
        "Ciphertext and plaintext data are the same. Invalid encryption"

    # 7. Decrypt your encrypted data using the same keyring you used on encrypt.
    plaintext_bytes, _ = client.decrypt(
        source=ciphertext,
        keyring=kms_keyring,
        # Provide the encryption context that was supplied to the encrypt method
        encryption_context=encryption_context,
    )

    # 8. Demonstrate that the decrypted plaintext is identical to the original plaintext.
    # (This is an example for demonstration; you do not need to do this in your own code.)
    assert plaintext_bytes == EXAMPLE_DATA, \
        "Decrypted plaintext should be identical to the original plaintext. Invalid decryption"
```

## 加密和解密位元組串流
<a name="python-example-streams"></a>

下列範例示範如何使用 AWS Encryption SDK 來加密和解密位元組串流。此範例使用[原始 AES keyring](use-raw-aes-keyring.md)。

此範例會使用[預設承諾政策](migrate-commitment-policy.md) 來執行個體化 AWS Encryption SDK 用戶端`REQUIRE_ENCRYPT_REQUIRE_DECRYPT`。如需詳細資訊，請參閱[設定您的承諾政策](migrate-commitment-policy.md)。

```
# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0
"""
This example demonstrates file streaming for encryption and decryption.

File streaming is useful when the plaintext or ciphertext file/data is too large to load into
memory. Therefore, the AWS Encryption SDK allows users to stream the data, instead of loading it
all at once in memory. In this example, we demonstrate file streaming for encryption and decryption
using a Raw AES keyring. However, you can use any keyring with streaming.

This example creates a Raw AES Keyring and then encrypts an input stream from the file
`plaintext_filename` with an encryption context to an output (encrypted) file `ciphertext_filename`.
It then decrypts the ciphertext from `ciphertext_filename` to a new file `decrypted_filename`.
This example also includes some sanity checks for demonstration:
1. Ciphertext and plaintext data are not the same
2. Encryption context is correct in the decrypted message header
3. Decrypted plaintext value matches EXAMPLE_DATA
These sanity checks are for demonstration in the example only. You do not need these in your code.

See raw_aes_keyring_example.py in the same directory for another raw AES keyring example
in the AWS Encryption SDK for Python.
"""
import filecmp
import secrets

from aws_cryptographic_material_providers.mpl import AwsCryptographicMaterialProviders
from aws_cryptographic_material_providers.mpl.config import MaterialProvidersConfig
from aws_cryptographic_material_providers.mpl.models import AesWrappingAlg, CreateRawAesKeyringInput
from aws_cryptographic_material_providers.mpl.references import IKeyring
from typing import Dict  # noqa pylint: disable=wrong-import-order

import aws_encryption_sdk
from aws_encryption_sdk import CommitmentPolicy


def encrypt_and_decrypt_with_keyring(
    plaintext_filename: str,
    ciphertext_filename: str,
    decrypted_filename: str
):
    """Demonstrate a streaming encrypt/decrypt cycle.

    Usage: encrypt_and_decrypt_with_keyring(plaintext_filename
                                            ciphertext_filename
                                            decrypted_filename)
    :param plaintext_filename: filename of the plaintext data
    :type plaintext_filename: string
    :param ciphertext_filename: filename of the ciphertext data
    :type ciphertext_filename: string
    :param decrypted_filename: filename of the decrypted data
    :type decrypted_filename: string
    """
    # 1. Instantiate the encryption SDK client.
    # This builds the client with the REQUIRE_ENCRYPT_REQUIRE_DECRYPT commitment policy,
    # which enforces that this client only encrypts using committing algorithm suites and enforces
    # that this client will only decrypt encrypted messages that were created with a committing
    # algorithm suite.
    # This is the default commitment policy if you were to build the client as
    # `client = aws_encryption_sdk.EncryptionSDKClient()`.
    client = aws_encryption_sdk.EncryptionSDKClient(
        commitment_policy=CommitmentPolicy.REQUIRE_ENCRYPT_REQUIRE_DECRYPT
    )

    # 2. The key namespace and key name are defined by you.
    # and are used by the Raw AES keyring to determine
    # whether it should attempt to decrypt an encrypted data key.
    key_name_space = "Some managed raw keys"
    key_name = "My 256-bit AES wrapping key"

    # 3. Optional: create encryption context.
    # Remember that your encryption context is NOT SECRET.
    encryption_context: Dict[str, str] = {
        "encryption": "context",
        "is not": "secret",
        "but adds": "useful metadata",
        "that can help you": "be confident that",
        "the data you are handling": "is what you think it is",
    }

    # 4. Generate a 256-bit AES key to use with your keyring.
    # In practice, you should get this key from a secure key management system such as an HSM.

    # Here, the input to secrets.token_bytes() = 32 bytes = 256 bits
    static_key = secrets.token_bytes(32)

    # 5. Create a Raw AES keyring
    # We choose to use a raw AES keyring, but any keyring can be used with streaming.
    mat_prov: AwsCryptographicMaterialProviders = AwsCryptographicMaterialProviders(
        config=MaterialProvidersConfig()
    )

    keyring_input: CreateRawAesKeyringInput = CreateRawAesKeyringInput(
        key_namespace=key_name_space,
        key_name=key_name,
        wrapping_key=static_key,
        wrapping_alg=AesWrappingAlg.ALG_AES256_GCM_IV12_TAG16
    )

    raw_aes_keyring: IKeyring = mat_prov.create_raw_aes_keyring(
        input=keyring_input
    )

    # 6. Encrypt the data stream with the encryptionContext
    with open(plaintext_filename, 'rb') as pt_file, open(ciphertext_filename, 'wb') as ct_file:
        with client.stream(
            mode='e',
            source=pt_file,
            keyring=raw_aes_keyring,
            encryption_context=encryption_context
        ) as encryptor:
            for chunk in encryptor:
                ct_file.write(chunk)

    # 7. Demonstrate that the ciphertext and plaintext are different.
    # (This is an example for demonstration; you do not need to do this in your own code.)
    assert not filecmp.cmp(plaintext_filename, ciphertext_filename), \
        "Ciphertext and plaintext data are the same. Invalid encryption"

    # 8. Decrypt your encrypted data stream using the same keyring you used on encrypt.
    with open(ciphertext_filename, 'rb') as ct_file, open(decrypted_filename, 'wb') as pt_file:
        with client.stream(
            mode='d',
            source=ct_file,
            keyring=raw_aes_keyring,
            encryption_context=encryption_context
        ) as decryptor:
            for chunk in decryptor:
                pt_file.write(chunk)

    # 10. Demonstrate that the decrypted plaintext is identical to the original plaintext.
    # (This is an example for demonstration; you do not need to do this in your own code.)
    assert filecmp.cmp(plaintext_filename, decrypted_filename), \
        "Decrypted plaintext should be identical to the original plaintext. Invalid decryption"
```