Exemple #1
0
def test_raw_master_key_decrypts_what_raw_keyring_encrypts(
        encryption_materials_samples):
    test_raw_rsa_keyring = RawRSAKeyring.from_pem_encoding(
        key_namespace=_PROVIDER_ID,
        key_name=_KEY_ID,
        wrapping_algorithm=_WRAPPING_ALGORITHM,
        private_encoded_key=_PRIVATE_WRAPPING_KEY_PEM,
        public_encoded_key=_PUBLIC_WRAPPING_KEY_PEM,
    )

    # Creating an instance of a raw master key
    test_raw_master_key = RawMasterKey(
        key_id=_KEY_ID,
        provider_id=_PROVIDER_ID,
        wrapping_key=WrappingKey(
            wrapping_algorithm=_WRAPPING_ALGORITHM,
            wrapping_key=_PRIVATE_WRAPPING_KEY_PEM,
            wrapping_key_type=EncryptionKeyType.PRIVATE,
        ),
    )

    # Call on_encrypt function for the keyring
    encryption_materials = test_raw_rsa_keyring.on_encrypt(
        encryption_materials=encryption_materials_samples)

    # Check if plaintext data key encrypted by raw keyring is decrypted by raw master key
    raw_mkp_decrypted_data_key = test_raw_master_key.decrypt_data_key_from_list(
        encrypted_data_keys=encryption_materials._encrypted_data_keys,
        algorithm=encryption_materials.algorithm,
        encryption_context=encryption_materials.encryption_context,
    ).data_key

    assert encryption_materials.data_encryption_key.data_key == raw_mkp_decrypted_data_key
def raw_rsa_mkps_from_keyring(keyring):
    # type: (RawRSAKeyring) -> (MasterKeyProvider, MasterKeyProvider)
    """Constructs a private and public raw RSA MKP using the private key in the raw RSA keyring."""
    private_key = keyring._private_wrapping_key
    private_pem = private_key.private_bytes(
        encoding=serialization.Encoding.PEM,
        format=serialization.PrivateFormat.PKCS8,
        encryption_algorithm=serialization.NoEncryption(),
    )
    public_pem = private_key.public_key().public_bytes(
        encoding=serialization.Encoding.PEM,
        format=serialization.PublicFormat.SubjectPublicKeyInfo)
    private_key_mkp = RawMasterKey(
        provider_id=keyring.key_namespace,
        key_id=keyring.key_name,
        wrapping_key=WrappingKey(
            wrapping_algorithm=keyring._wrapping_algorithm,
            wrapping_key=private_pem,
            wrapping_key_type=EncryptionKeyType.PRIVATE,
        ),
    )
    public_key_mkp = RawMasterKey(
        provider_id=keyring.key_namespace,
        key_id=keyring.key_name,
        wrapping_key=WrappingKey(
            wrapping_algorithm=keyring._wrapping_algorithm,
            wrapping_key=public_pem,
            wrapping_key_type=EncryptionKeyType.PUBLIC,
        ),
    )
    return private_key_mkp, public_key_mkp
def test_raw_master_key_decrypts_what_raw_keyring_encrypts(
        encryption_materials_samples):

    # Initializing attributes
    key_namespace = _PROVIDER_ID
    key_name = _KEY_ID

    # Creating an instance of a raw AES keyring
    test_raw_aes_keyring = RawAESKeyring(
        key_namespace=key_namespace,
        key_name=key_name,
        wrapping_key=_WRAPPING_KEY,
    )

    # Creating an instance of a raw master key
    test_raw_master_key = RawMasterKey(
        key_id=test_raw_aes_keyring.key_name,
        provider_id=test_raw_aes_keyring.key_namespace,
        wrapping_key=test_raw_aes_keyring._wrapping_key_structure,
    )

    # Encrypt using raw AES keyring
    encryption_materials = test_raw_aes_keyring.on_encrypt(
        encryption_materials=encryption_materials_samples)

    # Check if plaintext data key encrypted by raw keyring is decrypted by raw master key

    raw_mkp_decrypted_data_key = test_raw_master_key.decrypt_data_key_from_list(
        encrypted_data_keys=encryption_materials._encrypted_data_keys,
        algorithm=encryption_materials.algorithm,
        encryption_context=encryption_materials.encryption_context,
    ).data_key

    assert encryption_materials.data_encryption_key.data_key == raw_mkp_decrypted_data_key
 def test_owns_data_key_owned_symmetric(self, mock_prefix):
     self.mock_wrapping_key.wrapping_algorithm = WrappingAlgorithm.AES_256_GCM_IV12_TAG16_NO_PADDING
     test_master_key = RawMasterKey(
         key_id=VALUES['wrapped_keys']['raw']['key_info'],
         provider_id=VALUES['provider_id'],
         wrapping_key=self.mock_wrapping_key)
     assert test_master_key.owns_data_key(
         data_key=DataKey(key_provider=MasterKeyInfo(
             provider_id=VALUES['provider_id'],
             key_info=VALUES['wrapped_keys']['serialized']['key_info']),
                          encrypted_data_key=VALUES['encrypted_data_key'],
                          data_key=VALUES['data_key']))
 def test_owns_data_key_not_owned_asymmetric_checking_symmetric(self):
     self.mock_wrapping_key.wrapping_algorithm = WrappingAlgorithm.RSA_OAEP_SHA1_MGF1
     test_master_key = RawMasterKey(
         key_id=VALUES['wrapped_keys']['raw']['key_info'],
         provider_id=VALUES['provider_id'],
         wrapping_key=self.mock_wrapping_key)
     assert not test_master_key.owns_data_key(
         data_key=DataKey(key_provider=MasterKeyInfo(
             provider_id=VALUES['provider_id'],
             key_info=VALUES['wrapped_keys']['serialized']['key_info']),
                          encrypted_data_key=VALUES['encrypted_data_key'],
                          data_key=VALUES['data_key']))
Exemple #6
0
 def test_owns_data_key_not_owned_asymmetric_checking_symmetric(self):
     self.mock_wrapping_key.wrapping_algorithm = WrappingAlgorithm.RSA_OAEP_SHA1_MGF1
     test_master_key = RawMasterKey(
         key_id=VALUES["wrapped_keys"]["raw"]["key_info"],
         provider_id=VALUES["provider_id"],
         wrapping_key=self.mock_wrapping_key,
     )
     assert not test_master_key.owns_data_key(data_key=DataKey(
         key_provider=MasterKeyInfo(provider_id=VALUES["provider_id"],
                                    key_info=VALUES["wrapped_keys"]
                                    ["serialized"]["key_info"]),
         encrypted_data_key=VALUES["encrypted_data_key"],
         data_key=VALUES["data_key"],
     ))
Exemple #7
0
 def test_owns_data_key_owned_symmetric(self, mock_prefix):
     self.mock_wrapping_key.wrapping_algorithm = WrappingAlgorithm.AES_256_GCM_IV12_TAG16_NO_PADDING
     test_master_key = RawMasterKey(
         key_id=VALUES["wrapped_keys"]["raw"]["key_info"],
         provider_id=VALUES["provider_id"],
         wrapping_key=self.mock_wrapping_key,
     )
     assert test_master_key.owns_data_key(data_key=DataKey(
         key_provider=MasterKeyInfo(provider_id=VALUES["provider_id"],
                                    key_info=VALUES["wrapped_keys"]
                                    ["serialized"]["key_info"]),
         encrypted_data_key=VALUES["encrypted_data_key"],
         data_key=VALUES["data_key"],
     ))
Exemple #8
0
 def test_init(self):
     test = RawMasterKey(
         key_id=VALUES["wrapped_keys"]["raw"]["key_info"],
         provider_id=VALUES["provider_id"],
         wrapping_key=self.mock_wrapping_key,
     )
     assert test.provider_id == VALUES["provider_id"]
 def test_decrypt_data_key(self, mock_wrapped_deserialize):
     test_master_key = RawMasterKey(
         key_id=VALUES['wrapped_keys']['raw']['key_info'],
         provider_id=VALUES['provider_id'],
         wrapping_key=self.mock_wrapping_key)
     test = test_master_key._decrypt_data_key(
         encrypted_data_key=self.mock_encrypted_data_key,
         algorithm=self.mock_algorithm,
         encryption_context=sentinel.encryption_context)
     mock_wrapped_deserialize.assert_called_once_with(
         wrapping_algorithm=self.mock_wrapping_algorithm,
         wrapping_key_id=VALUES['wrapped_keys']['raw']['key_info'],
         wrapped_encrypted_key=self.mock_encrypted_data_key)
     self.mock_wrapping_key.decrypt.assert_called_once_with(
         encrypted_wrapped_data_key=sentinel.encrypted_wrapped_key,
         encryption_context=sentinel.encryption_context)
     assert test == self.mock_data_key
 def test_generate_data_key(self, mock_encrypt_data_key, mock_urandom,
                            mock_key_len_check):
     mock_urandom.return_value = VALUES['data_key']
     mock_encrypt_data_key.return_value = self.mock_encrypted_data_key
     test_master_key = RawMasterKey(
         key_id=VALUES['wrapped_keys']['raw']['key_info'],
         provider_id=VALUES['provider_id'],
         wrapping_key=self.mock_wrapping_key)
     test = test_master_key.generate_data_key(
         algorithm=self.mock_algorithm,
         encryption_context=VALUES['encryption_context'])
     mock_urandom.assert_called_once_with(sentinel.kdf_input_len)
     mock_encrypt_data_key.assert_called_once_with(
         data_key=RawDataKey(key_provider=test_master_key.key_provider,
                             data_key=VALUES['data_key']),
         algorithm=self.mock_algorithm,
         encryption_context=VALUES['encryption_context'])
     assert test == self.mock_data_key
 def test_encrypt_data_key(self, mock_wrapped_serialize):
     test_master_key = RawMasterKey(
         key_id=VALUES['wrapped_keys']['raw']['key_info'],
         provider_id=VALUES['provider_id'],
         wrapping_key=self.mock_wrapping_key)
     test = test_master_key._encrypt_data_key(
         data_key=self.mock_data_key,
         algorithm=sentinel.algorithm,
         encryption_context=sentinel.encryption_context)
     self.mock_wrapping_key.encrypt.assert_called_once_with(
         plaintext_data_key=VALUES['data_key'],
         encryption_context=sentinel.encryption_context)
     mock_wrapped_serialize.assert_called_once_with(
         key_provider=test_master_key.key_provider,
         wrapping_algorithm=self.mock_wrapping_algorithm,
         wrapping_key_id=VALUES['wrapped_keys']['raw']['key_info'],
         encrypted_wrapped_key=sentinel.encrypted_data)
     assert test is sentinel.wrapped_key
Exemple #12
0
def test_raw_keyring_decrypts_what_raw_master_key_encrypts(
        encryption_materials_samples):

    # Create instance of raw master key
    test_raw_master_key = RawMasterKey(
        key_id=_KEY_ID,
        provider_id=_PROVIDER_ID,
        wrapping_key=WrappingKey(
            wrapping_algorithm=_WRAPPING_ALGORITHM,
            wrapping_key=_PRIVATE_WRAPPING_KEY_PEM,
            wrapping_key_type=EncryptionKeyType.PRIVATE,
        ),
    )

    test_raw_rsa_keyring = RawRSAKeyring.from_pem_encoding(
        key_namespace=_PROVIDER_ID,
        key_name=_KEY_ID,
        wrapping_algorithm=_WRAPPING_ALGORITHM,
        private_encoded_key=_PRIVATE_WRAPPING_KEY_PEM,
        public_encoded_key=_PUBLIC_WRAPPING_KEY_PEM,
    )

    raw_mkp_generated_data_key = test_raw_master_key.generate_data_key(
        algorithm=encryption_materials_samples.algorithm,
        encryption_context=encryption_materials_samples.encryption_context,
    )

    raw_mkp_encrypted_data_key = test_raw_master_key.encrypt_data_key(
        data_key=raw_mkp_generated_data_key,
        algorithm=encryption_materials_samples.algorithm,
        encryption_context=encryption_materials_samples.encryption_context,
    )

    decryption_materials = test_raw_rsa_keyring.on_decrypt(
        decryption_materials=DecryptionMaterials(
            algorithm=encryption_materials_samples.algorithm,
            encryption_context=encryption_materials_samples.encryption_context,
            verification_key=b"ex_verification_key",
        ),
        encrypted_data_keys=[raw_mkp_encrypted_data_key],
    )

    assert raw_mkp_generated_data_key.data_key == decryption_materials.data_encryption_key.data_key
def test_key_info_prefix_vectors(wrapping_algorithm):
    assert (serialize_raw_master_key_prefix(raw_master_key=RawMasterKey(
        provider_id=_PROVIDER_ID,
        key_id=_KEY_ID,
        wrapping_key=WrappingKey(
            wrapping_algorithm=wrapping_algorithm,
            wrapping_key=_WRAPPING_KEY,
            wrapping_key_type=EncryptionKeyType.SYMMETRIC,
        ),
    )) == _KEY_ID + b"\x00\x00\x00\x80\x00\x00\x00\x0c")
Exemple #14
0
 def test_generate_data_key(self, mock_encrypt_data_key, mock_urandom,
                            mock_key_len_check):
     mock_urandom.return_value = VALUES["data_key"]
     mock_encrypt_data_key.return_value = self.mock_encrypted_data_key
     test_master_key = RawMasterKey(
         key_id=VALUES["wrapped_keys"]["raw"]["key_info"],
         provider_id=VALUES["provider_id"],
         wrapping_key=self.mock_wrapping_key,
     )
     test = test_master_key.generate_data_key(
         algorithm=self.mock_algorithm,
         encryption_context=VALUES["encryption_context"])
     mock_urandom.assert_called_once_with(sentinel.kdf_input_len)
     mock_encrypt_data_key.assert_called_once_with(
         data_key=RawDataKey(key_provider=test_master_key.key_provider,
                             data_key=VALUES["data_key"]),
         algorithm=self.mock_algorithm,
         encryption_context=VALUES["encryption_context"],
     )
     assert test == self.mock_data_key
Exemple #15
0
 def test_encrypt_data_key(self, mock_wrapped_serialize):
     test_master_key = RawMasterKey(
         key_id=VALUES["wrapped_keys"]["raw"]["key_info"],
         provider_id=VALUES["provider_id"],
         wrapping_key=self.mock_wrapping_key,
     )
     test = test_master_key._encrypt_data_key(
         data_key=self.mock_data_key,
         algorithm=sentinel.algorithm,
         encryption_context=sentinel.encryption_context)
     self.mock_wrapping_key.encrypt.assert_called_once_with(
         plaintext_data_key=VALUES["data_key"],
         encryption_context=sentinel.encryption_context)
     mock_wrapped_serialize.assert_called_once_with(
         key_provider=test_master_key.key_provider,
         wrapping_algorithm=self.mock_wrapping_algorithm,
         wrapping_key_id=VALUES["wrapped_keys"]["raw"]["key_info"],
         encrypted_wrapped_key=sentinel.encrypted_data,
     )
     assert test is sentinel.wrapped_key
def test_raw_keyring_decrypts_what_raw_master_key_encrypts(
        encryption_materials_samples):

    # Initializing attributes
    key_namespace = _PROVIDER_ID
    key_name = _KEY_ID

    # Creating an instance of a raw AES keyring
    test_raw_aes_keyring = RawAESKeyring(
        key_namespace=key_namespace,
        key_name=key_name,
        wrapping_key=_WRAPPING_KEY,
    )

    # Creating an instance of a raw master key
    test_raw_master_key = RawMasterKey(
        key_id=test_raw_aes_keyring.key_name,
        provider_id=test_raw_aes_keyring.key_namespace,
        wrapping_key=test_raw_aes_keyring._wrapping_key_structure,
    )

    if encryption_materials_samples.data_encryption_key is None:
        return
    raw_master_key_encrypted_data_key = test_raw_master_key.encrypt_data_key(
        data_key=encryption_materials_samples.data_encryption_key,
        algorithm=encryption_materials_samples.algorithm,
        encryption_context=encryption_materials_samples.encryption_context,
    )

    # Check if plaintext data key encrypted by raw master key is decrypted by raw keyring

    raw_aes_keyring_decrypted_data_key = test_raw_aes_keyring.on_decrypt(
        decryption_materials=DecryptionMaterials(
            algorithm=encryption_materials_samples.algorithm,
            encryption_context=encryption_materials_samples.encryption_context,
            verification_key=b"ex_verification_key",
        ),
        encrypted_data_keys=[raw_master_key_encrypted_data_key],
    ).data_encryption_key.data_key

    assert encryption_materials_samples.data_encryption_key.data_key == raw_aes_keyring_decrypted_data_key
def ephemeral_raw_rsa_master_key(size=4096):
    # type: (int) -> RawMasterKey
    key_bytes = _generate_rsa_key_bytes(size)
    return RawMasterKey(
        provider_id="fake",
        key_id="rsa-{}".format(size).encode("utf-8"),
        wrapping_key=WrappingKey(
            wrapping_algorithm=WrappingAlgorithm.RSA_OAEP_SHA256_MGF1,
            wrapping_key=key_bytes,
            wrapping_key_type=EncryptionKeyType.PRIVATE,
        ),
    )
    def _get_key_info_prefix(key_namespace, key_name, wrapping_key):
        # type: (str, bytes, WrappingKey) -> six.binary_type
        """Helper function to get key info prefix

        :param str key_namespace: String defining the keyring.
        :param bytes key_name: Key ID
        :param WrappingKey wrapping_key: Encryption key with which to wrap plaintext data key.
        :return: Serialized key_info prefix
        :rtype: bytes
        """
        key_info_prefix = serialize_raw_master_key_prefix(
            RawMasterKey(provider_id=key_namespace,
                         key_id=key_name,
                         wrapping_key=wrapping_key))
        return key_info_prefix
    def _raw_master_key_from_spec(self, key_spec):
        # type: (KeySpec) -> RawMasterKey
        """Build a raw master key using this specification.

        :param KeySpec key_spec: Key specification to use with this master key
        :return: Raw master key based on this specification
        :rtype: RawMasterKey
        :raises TypeError: if this is not a raw master key specification
        """
        if not self.type_name == "raw":
            raise TypeError("This is not a raw master key")

        wrapping_key = self._wrapping_key(key_spec)
        key_id = self._raw_key_id()
        return RawMasterKey(provider_id=self.provider_id, key_id=key_id, wrapping_key=wrapping_key)
def _keys_to_mkp(keys):
    if len(keys) > 1:
        return RawMultiMKP(valid_key_ids=[key["key_id"] for key in keys])

    _key = keys[0]
    return RawMasterKey(
        provider_id=_PROVIDER_ID,
        key_id=_key["key_id"],
        wrapping_key=WrappingKey(
            wrapping_algorithm=WrappingAlgorithm.
            AES_256_GCM_IV12_TAG16_NO_PADDING,
            wrapping_key=_key["wrapping_key"],
            wrapping_key_type=EncryptionKeyType.SYMMETRIC,
        ),
    )
def ephemeral_raw_aes_master_key(
        wrapping_algorithm=WrappingAlgorithm.AES_256_GCM_IV12_TAG16_NO_PADDING,
        key=None):
    # type: (WrappingAlgorithm, Optional[bytes]) -> RawMasterKey
    key_length = wrapping_algorithm.algorithm.data_key_len
    if key is None:
        key = os.urandom(key_length)
    return RawMasterKey(
        provider_id="fake",
        key_id="aes-{}".format(key_length * 8).encode("utf-8"),
        wrapping_key=WrappingKey(
            wrapping_algorithm=wrapping_algorithm,
            wrapping_key=key,
            wrapping_key_type=EncryptionKeyType.SYMMETRIC,
        ),
    )
def run(source_plaintext):
    # type: (bytes) -> None
    """Demonstrate an encrypt/decrypt cycle using a raw AES master key.

    :param bytes source_plaintext: Plaintext to encrypt
    """
    # Prepare your encryption context.
    # 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",
    }

    # Choose the wrapping algorithm for your master key to use.
    wrapping_algorithm = WrappingAlgorithm.AES_256_GCM_IV12_TAG16_NO_PADDING

    # Generate an AES key to use with your master key.
    # The key size depends on the wrapping algorithm.
    #
    # In practice, you should get this key from a secure key management system such as an HSM.
    key = os.urandom(wrapping_algorithm.algorithm.kdf_input_len)

    # Create the master key that determines how your data keys are protected.
    master_key = RawMasterKey(
        # The provider ID and key ID are defined by you
        # and are used by the raw AES 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 AES wrapping key",  # key ID corresponds to key name for keyrings
        wrapping_key=WrappingKey(
            wrapping_algorithm=wrapping_algorithm,
            wrapping_key_type=EncryptionKeyType.SYMMETRIC,
            wrapping_key=key,
        ),
    )

    # Encrypt your plaintext data.
    ciphertext, _encrypt_header = aws_encryption_sdk.encrypt(
        source=source_plaintext,
        encryption_context=encryption_context,
        key_provider=master_key)

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

    # Decrypt your encrypted data using the same master key you used on encrypt.
    #
    # You do not need to specify the encryption context on decrypt
    # because the header of the encrypted message includes the encryption context.
    decrypted, decrypt_header = aws_encryption_sdk.decrypt(
        source=ciphertext, key_provider=master_key)

    # Demonstrate that the decrypted plaintext is identical to the original plaintext.
    assert decrypted == 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.encryption_context.items())
 def test_init(self):
     test = RawMasterKey(key_id=VALUES['wrapped_keys']['raw']['key_info'],
                         provider_id=VALUES['provider_id'],
                         wrapping_key=self.mock_wrapping_key)
     assert test.provider_id == VALUES['provider_id']
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())
def run(source_plaintext):
    # type: (bytes) -> None
    """Demonstrate an encrypt/decrypt cycle using a raw RSA master key loaded from a PEM-encoded key.

    :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(),
    )

    # Create the master key that determines how your data keys are protected.
    #
    # WrappingKey can only load PEM-encoded keys.
    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=private_key_pem,
            wrapping_key_type=EncryptionKeyType.PRIVATE,
            # 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,
        ),
    )

    # Encrypt your plaintext data.
    ciphertext, _encrypt_header = aws_encryption_sdk.encrypt(
        source=source_plaintext,
        encryption_context=encryption_context,
        key_provider=master_key)

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

    # Decrypt your encrypted data using the same master key you used on encrypt.
    #
    # You do not need to specify the encryption context on decrypt
    # because the header of the encrypted message includes the encryption context.
    decrypted, decrypt_header = aws_encryption_sdk.decrypt(
        source=ciphertext, key_provider=master_key)

    # Demonstrate that the decrypted plaintext is identical to the original plaintext.
    assert decrypted == 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.encryption_context.items())