def run(aws_kms_cmk, source_plaintext):
    # type: (str, bytes) -> None
    """Demonstrate configuring a master key provider to use an AWS KMS CMK and an RSA wrapping key.

    :param str aws_kms_cmk: The ARN of an AWS KMS CMK that protects data keys
    :param bytes source_plaintext: Plaintext to encrypt
    """
    # Prepare your encryption context.
    # Remember that your encryption context is NOT SECRET.
    # https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/concepts.html#encryption-context
    encryption_context = {
        "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",
    }

    # Generate an RSA private key to use with your master key.
    # In practice, you should get this key from a secure key management system such as an HSM.
    #
    # The National Institute of Standards and Technology (NIST) recommends a minimum of 2048-bit keys for RSA.
    # https://www.nist.gov/publications/transitioning-use-cryptographic-algorithms-and-key-lengths
    #
    # Why did we use this public exponent?
    # https://crypto.stanford.edu/~dabo/pubs/papers/RSA-survey.pdf
    private_key = rsa.generate_private_key(public_exponent=65537,
                                           key_size=4096,
                                           backend=default_backend())

    # Serialize the RSA private key to PEM encoding.
    # This or DER encoding is likely to be what you get from your key management system in practice.
    private_key_pem = private_key.private_bytes(
        encoding=serialization.Encoding.PEM,
        format=serialization.PrivateFormat.PKCS8,
        encryption_algorithm=serialization.NoEncryption(),
    )

    # Collect the public key from the private key.
    public_key = private_key.public_key()

    # Serialize the RSA public key to PEM encoding.
    # This or DER encoding is likely to be what you get from your key management system in practice.
    public_key_pem = public_key.public_bytes(
        encoding=serialization.Encoding.PEM,
        format=serialization.PublicFormat.SubjectPublicKeyInfo,
    )

    # Create the encrypt master key that only has access to the public key.
    escrow_encrypt_master_key = RawMasterKey(
        # The provider ID and key ID are defined by you
        # and are used by the raw RSA master key
        # to determine whether it should attempt to decrypt
        # an encrypted data key.
        provider_id=
        "some managed raw keys",  # provider ID corresponds to key namespace for keyrings
        key_id=
        b"my RSA wrapping key",  # key ID corresponds to key name for keyrings
        wrapping_key=WrappingKey(
            wrapping_key=public_key_pem,
            wrapping_key_type=EncryptionKeyType.PUBLIC,
            # The wrapping algorithm tells the raw RSA master key
            # how to use your wrapping key to encrypt data keys.
            #
            # We recommend using RSA_OAEP_SHA256_MGF1.
            # You should not use RSA_PKCS1 unless you require it for backwards compatibility.
            wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1,
        ),
    )

    # Create the decrypt master key that has access to the private key.
    escrow_decrypt_master_key = RawMasterKey(
        # The key namespace and key name MUST match the encrypt master key.
        provider_id=
        "some managed raw keys",  # provider ID corresponds to key namespace for keyrings
        key_id=
        b"my RSA wrapping key",  # key ID corresponds to key name for keyrings
        wrapping_key=WrappingKey(
            wrapping_key=private_key_pem,
            wrapping_key_type=EncryptionKeyType.PRIVATE,
            # The wrapping algorithm MUST match the encrypt master key.
            wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1,
        ),
    )

    # Create the AWS KMS master key that you will use for decryption during normal operations.
    kms_master_key = KMSMasterKeyProvider(key_ids=[aws_kms_cmk])

    # Add the escrow encrypt master key to the AWS KMS master key.
    kms_master_key.add_master_key_provider(escrow_encrypt_master_key)

    # Encrypt your plaintext data using the combined master keys.
    ciphertext, encrypt_header = aws_encryption_sdk.encrypt(
        source=source_plaintext,
        encryption_context=encryption_context,
        key_provider=kms_master_key)

    # Verify that the header contains the expected number of encrypted data keys (EDKs).
    # It should contain one EDK for AWS KMS and one for the escrow key.
    assert len(encrypt_header.encrypted_data_keys) == 2

    # Demonstrate that the ciphertext and plaintext are different.
    assert ciphertext != source_plaintext

    # Decrypt your encrypted data separately using the AWS KMS master key and the escrow decrypt master key.
    #
    # You do not need to specify the encryption context on decrypt
    # because the header of the encrypted message includes the encryption context.
    decrypted_kms, decrypt_header_kms = aws_encryption_sdk.decrypt(
        source=ciphertext, key_provider=kms_master_key)
    decrypted_escrow, decrypt_header_escrow = aws_encryption_sdk.decrypt(
        source=ciphertext, key_provider=escrow_decrypt_master_key)

    # Demonstrate that the decrypted plaintext is identical to the original plaintext.
    assert decrypted_kms == source_plaintext
    assert decrypted_escrow == source_plaintext

    # Verify that the encryption context used in the decrypt operation includes
    # the encryption context that you specified when encrypting.
    # The AWS Encryption SDK can add pairs, so don't require an exact match.
    #
    # In production, always use a meaningful encryption context.
    assert set(encryption_context.items()) <= set(
        decrypt_header_kms.encryption_context.items())
    assert set(encryption_context.items()) <= set(
        decrypt_header_escrow.encryption_context.items())
Beispiel #2
0
def _master_key_provider() -> KMSMasterKeyProvider:
    """Build the V0 master key provider."""
    master_key_provider = KMSMasterKeyProvider()
    master_key_provider.add_master_key_provider(NullMasterKey())
    master_key_provider.add_master_key_provider(CountingMasterKey())
    return master_key_provider