def deserialize_encrypted_data_keys(stream, max_encrypted_data_keys=None):
    # type: (IO, Union[int, None]) -> Set[EncryptedDataKey]
    """Deserialize some encrypted data keys from a stream.

    :param stream: Stream from which to read encrypted data keys
    :param max_encrypted_data_keys: Maximum number of encrypted data keys to deserialize
    :return: Loaded encrypted data keys
    :rtype: set of :class:`EncryptedDataKey`
    """
    (encrypted_data_key_count, ) = unpack_values(">H", stream)
    if max_encrypted_data_keys and encrypted_data_key_count > max_encrypted_data_keys:
        raise MaxEncryptedDataKeysExceeded(encrypted_data_key_count,
                                           max_encrypted_data_keys)
    encrypted_data_keys = set([])
    for _ in range(encrypted_data_key_count):
        (key_provider_length, ) = unpack_values(">H", stream)
        (key_provider_identifier, ) = unpack_values(
            ">{}s".format(key_provider_length), stream)
        (key_provider_information_length, ) = unpack_values(">H", stream)
        (key_provider_information, ) = unpack_values(
            ">{}s".format(key_provider_information_length), stream)
        (encrypted_data_key_length, ) = unpack_values(">H", stream)
        encrypted_data_key = stream.read(encrypted_data_key_length)
        encrypted_data_keys.add(
            EncryptedDataKey(
                key_provider=MasterKeyInfo(
                    provider_id=to_str(key_provider_identifier),
                    key_info=key_provider_information),
                encrypted_data_key=encrypted_data_key,
            ))
    return encrypted_data_keys
Example #2
0
    def test_encrypt_data_key(self, config_class, key_class, key_id):
        config = config_class(key_id=key_id, client=self.mock_client)
        test = key_class(config=config)
        self.mock_client.encrypt.return_value["KeyId"] = key_id
        # //= compliance/framework/aws-kms/aws-kms-mrk-aware-master-key.txt#2.11
        # //= type=test
        # //# The inputs MUST be the same as the Master Key Encrypt Data Key
        # //# (../master-key-interface.md#encrypt-data-key) interface.
        encrypted_key = test._encrypt_data_key(self.mock_data_key,
                                               self.mock_algorithm)

        # //= compliance/framework/aws-kms/aws-kms-mrk-aware-master-key.txt#2.11
        # //= type=test
        # //# The master key MUST use the configured AWS KMS client to make an AWS KMS Encrypt
        # //# (https://docs.aws.amazon.com/kms/latest/APIReference/
        # //# API_Encrypt.html) request constructed as follows:
        self.mock_client.encrypt.assert_called_once_with(
            KeyId=key_id.decode("ascii"), Plaintext=VALUES["data_key"])

        # //= compliance/framework/aws-kms/aws-kms-mrk-aware-master-key.txt#2.11
        # //= type=test
        # //# The response's cipher text blob MUST be used as the "ciphertext" for the
        # //# encrypted data key.

        # //= compliance/framework/aws-kms/aws-kms-mrk-aware-master-key.txt#2.11
        # //= type=test
        # //# The output MUST be the same as the Master Key Encrypt Data Key
        # //# (../master-key-interface.md#encrypt-data-key) interface.
        assert encrypted_key == EncryptedDataKey(
            key_provider=MasterKeyInfo(provider_id=test.provider_id,
                                       key_info=key_id.decode("ascii")),
            encrypted_data_key=VALUES["encrypted_data_key"],
        )
    def _encrypt_data_key(self, data_key, algorithm, encryption_context=None):
        """Encrypts a data key and returns the ciphertext.

        :param data_key: Unencrypted data key
        :type data_key: :class:`aws_encryption_sdk.structures.RawDataKey`
            or :class:`aws_encryption_sdk.structures.DataKey`
        :param algorithm: Placeholder to maintain API compatibility with parent
        :param dict encryption_context: Encryption context to pass to KMS
        :returns: Data key containing encrypted data key
        :rtype: aws_encryption_sdk.structures.EncryptedDataKey
        :raises EncryptKeyError: if Master Key is unable to encrypt data key
        """
        kms_params = {"KeyId": self._key_id, "Plaintext": data_key.data_key}
        if encryption_context:
            kms_params["EncryptionContext"] = encryption_context
        if self.config.grant_tokens:
            kms_params["GrantTokens"] = self.config.grant_tokens
        # Catch any boto3 errors and normalize to expected EncryptKeyError
        try:
            response = self.config.client.encrypt(**kms_params)
            ciphertext = response["CiphertextBlob"]
            key_id = response["KeyId"]
        except (ClientError, KeyError):
            error_message = "Master Key {key_id} unable to encrypt data key".format(
                key_id=self._key_id)
            _LOGGER.exception(error_message)
            raise EncryptKeyError(error_message)
        return EncryptedDataKey(key_provider=MasterKeyInfo(
            provider_id=self.provider_id, key_info=key_id),
                                encrypted_data_key=ciphertext)
Example #4
0
def test_aws_kms_discovery_keyring_on_decrypt_existing_data_key(caplog):
    # In this context there are no KMS CMKs, so any calls to KMS will fail.
    caplog.set_level(logging.DEBUG)
    keyring = _AwsKmsDiscoveryKeyring(client_supplier=DefaultClientSupplier())

    initial_materials = DecryptionMaterials(
        algorithm=ALGORITHM,
        encryption_context={},
        data_encryption_key=RawDataKey(
            key_provider=MasterKeyInfo(provider_id="foo", key_info=b"bar"), data_key=os.urandom(ALGORITHM.kdf_input_len)
        ),
    )

    result_materials = keyring.on_decrypt(
        decryption_materials=initial_materials,
        encrypted_data_keys=(
            EncryptedDataKey(
                key_provider=MasterKeyInfo(provider_id=KEY_NAMESPACE, key_info=b"foo"), encrypted_data_key=b"bar"
            ),
        ),
    )

    assert result_materials.data_encryption_key == initial_materials.data_encryption_key

    log_data = caplog.text
    # This means that it did NOT try to decrypt the EDK.
    assert "Unable to decrypt encrypted data key from" not in log_data
def get_encryption_materials_with_encrypted_data_key():
    return EncryptionMaterials(
        algorithm=AlgorithmSuite.AES_256_GCM_IV12_TAG16_HKDF_SHA384_ECDSA_P384,
        data_encryption_key=RawDataKey(
            key_provider=MasterKeyInfo(provider_id=_PROVIDER_ID,
                                       key_info=_EXISTING_KEY_ID),
            data_key=
            b'*!\xa1"^-(\xf3\x105\x05i@B\xc2\xa2\xb7\xdd\xd5\xd5\xa9\xddm\xfae\xa8\\$\xf9d\x1e(',
        ),
        encrypted_data_keys=[
            EncryptedDataKey(
                key_provider=MasterKeyInfo(provider_id=_PROVIDER_ID,
                                           key_info=_EXISTING_KEY_ID),
                encrypted_data_key=
                b"\xde^\x97\x7f\x84\xe9\x9e\x98\xd0\xe2\xf8\xd5\xcb\xe9\x7f.}\x87\x16,\x11n#\xc8p"
                b"\xdb\xbf\x94\x86*Q\x06\xd2\xf5\xdah\x08\xa4p\x81\xf7\xf4G\x07FzE\xde",
            )
        ],
        encryption_context=_ENCRYPTION_CONTEXT,
        signing_key=_SIGNING_KEY,
        keyring_trace=[
            KeyringTrace(
                wrapping_key=MasterKeyInfo(provider_id=_PROVIDER_ID,
                                           key_info=_EXISTING_KEY_ID),
                flags={
                    KeyringTraceFlag.GENERATED_DATA_KEY,
                    KeyringTraceFlag.ENCRYPTED_DATA_KEY
                },
            )
        ],
    )
def _deserialize_encrypted_data_keys(stream):
    # type: (IO) -> Set[EncryptedDataKey]
    """Deserialize some encrypted data keys from a stream.

    :param stream: Stream from which to read encrypted data keys
    :return: Loaded encrypted data keys
    :rtype: set of :class:`EncryptedDataKey`
    """
    (encrypted_data_key_count,) = unpack_values(">H", stream)
    encrypted_data_keys = set([])
    for _ in range(encrypted_data_key_count):
        (key_provider_length,) = unpack_values(">H", stream)
        (key_provider_identifier,) = unpack_values(">{}s".format(key_provider_length), stream)
        (key_provider_information_length,) = unpack_values(">H", stream)
        (key_provider_information,) = unpack_values(">{}s".format(key_provider_information_length), stream)
        (encrypted_data_key_length,) = unpack_values(">H", stream)
        encrypted_data_key = stream.read(encrypted_data_key_length)
        encrypted_data_keys.add(
            EncryptedDataKey(
                key_provider=MasterKeyInfo(
                    provider_id=to_str(key_provider_identifier), key_info=key_provider_information
                ),
                encrypted_data_key=encrypted_data_key,
            )
        )
    return encrypted_data_keys
Example #7
0
def serialize_wrapped_key(key_provider, wrapping_algorithm, wrapping_key_id,
                          encrypted_wrapped_key):
    """Serializes EncryptedData into a Wrapped EncryptedDataKey.

    :param key_provider: Info for Wrapping MasterKey
    :type key_provider: aws_encryption_sdk.structure.MasterKeyInfo
    :param wrapping_algorithm: Wrapping Algorithm with which to wrap plaintext_data_key
    :type wrapping_algorithm: aws_encryption_sdk.identifiers.WrappingAlgorithm
    :param bytes wrapping_key_id: Key ID of wrapping MasterKey
    :param encrypted_wrapped_key: Encrypted data key
    :type encrypted_wrapped_key: aws_encryption_sdk.internal.structures.EncryptedData
    :returns: Wrapped EncryptedDataKey
    :rtype: aws_encryption_sdk.structure.EncryptedDataKey
    """
    if encrypted_wrapped_key.iv is None:
        key_info = wrapping_key_id
        key_ciphertext = encrypted_wrapped_key.ciphertext
    else:
        key_info = struct.pack(
            '>{key_id_len}sII{iv_len}s'.format(
                key_id_len=len(wrapping_key_id),
                iv_len=wrapping_algorithm.algorithm.iv_len),
            to_bytes(wrapping_key_id),
            len(encrypted_wrapped_key.tag) *
            8,  # Tag Length is stored in bits, not bytes
            wrapping_algorithm.algorithm.iv_len,
            encrypted_wrapped_key.iv)
        key_ciphertext = encrypted_wrapped_key.ciphertext + encrypted_wrapped_key.tag
    return EncryptedDataKey(key_provider=MasterKeyInfo(
        provider_id=key_provider.provider_id, key_info=key_info),
                            encrypted_data_key=key_ciphertext)
Example #8
0
def test_try_aws_kms_decrypt_succeed(fake_generator):
    encryption_context = {"foo": "bar"}
    kms = boto3.client("kms", region_name=FAKE_REGION)
    plaintext = b"0123" * 8
    response = kms.encrypt(KeyId=fake_generator, Plaintext=plaintext, EncryptionContext=encryption_context)

    encrypted_data_key = EncryptedDataKey(
        key_provider=MasterKeyInfo(provider_id=KEY_NAMESPACE, key_info=response["KeyId"]),
        encrypted_data_key=response["CiphertextBlob"],
    )

    initial_decryption_materials = DecryptionMaterials(algorithm=ALGORITHM, encryption_context=encryption_context,)

    result_materials = _try_aws_kms_decrypt(
        client_supplier=DefaultClientSupplier(),
        decryption_materials=initial_decryption_materials,
        grant_tokens=[],
        encrypted_data_key=encrypted_data_key,
    )

    assert result_materials.data_encryption_key.data_key == plaintext

    generator_flags = _matching_flags(
        MasterKeyInfo(provider_id=KEY_NAMESPACE, key_info=fake_generator), result_materials.keyring_trace
    )

    assert KeyringTraceFlag.DECRYPTED_DATA_KEY in generator_flags
    assert KeyringTraceFlag.VERIFIED_ENCRYPTION_CONTEXT in generator_flags
Example #9
0
 def test_prepare_data_keys(self):
     mock_encryption_dk = DataKey(
         key_provider=self.mock_key_provider_1,
         data_key=self.mock_raw_data_key_1_bytes,
         encrypted_data_key=self.mock_encrypted_data_key_1_bytes)
     mock_primary_mk = MagicMock()
     mock_primary_mk.generate_data_key.return_value = mock_encryption_dk
     mock_mk_1 = MagicMock()
     mock_mk_1.encrypt_data_key.return_value = sentinel.encrypted_data_key_1
     mock_mk_2 = MagicMock()
     mock_mk_2.encrypt_data_key.return_value = sentinel.encrypted_data_key_2
     test_data_encryption_key, test_encrypted_data_keys = aws_encryption_sdk.internal.utils.prepare_data_keys(
         primary_master_key=mock_primary_mk,
         master_keys=[mock_primary_mk, mock_mk_1, mock_mk_2],
         algorithm=sentinel.algorithm,
         encryption_context=sentinel.encryption_context)
     mock_primary_mk.generate_data_key.assert_called_once_with(
         sentinel.algorithm, sentinel.encryption_context)
     assert not mock_primary_mk.encrypt_data_key.called
     mock_mk_1.encrypt_data_key.assert_called_once_with(
         data_key=mock_encryption_dk,
         algorithm=sentinel.algorithm,
         encryption_context=sentinel.encryption_context)
     mock_mk_2.encrypt_data_key.assert_called_once_with(
         data_key=mock_encryption_dk,
         algorithm=sentinel.algorithm,
         encryption_context=sentinel.encryption_context)
     mock_encrypted_data_encryption_key = EncryptedDataKey(
         key_provider=self.mock_key_provider_1,
         encrypted_data_key=self.mock_encrypted_data_key_1_bytes)
     assert test_data_encryption_key is mock_encryption_dk
     assert test_encrypted_data_keys == set([
         mock_encrypted_data_encryption_key, sentinel.encrypted_data_key_1,
         sentinel.encrypted_data_key_2
     ])
Example #10
0
 def _encrypt_data_key(self, data_key, algorithm, encryption_context=None):
     encrypted_data_key = self._main_key.encrypt(data_key.data_key)
     return EncryptedDataKey(
         key_provider=MasterKeyInfo(
             provider_id=self.provider_id,
             key_info=self._main_key.key_id,
         ),
         encrypted_data_key=encrypted_data_key,
     )
Example #11
0
 def test_encrypt_data_key(self):
     test = KMSMasterKey(config=self.mock_kms_mkc_3)
     encrypted_key = test._encrypt_data_key(self.mock_data_key,
                                            self.mock_algorithm)
     self.mock_client.encrypt.assert_called_once_with(
         KeyId='ex_key_info', Plaintext=VALUES['data_key'])
     assert encrypted_key == EncryptedDataKey(
         key_provider=MasterKeyInfo(provider_id=test.provider_id,
                                    key_info=VALUES['arn']),
         encrypted_data_key=VALUES['encrypted_data_key'])
Example #12
0
 def test_serialize_wrapped_key_asymmetric(self):
     test = aws_encryption_sdk.internal.formatting.serialize.serialize_wrapped_key(
         key_provider=self.mock_key_provider,
         wrapping_algorithm=self.mock_wrapping_algorithm,
         wrapping_key_id=VALUES['wrapped_keys']['raw']['key_info'],
         encrypted_wrapped_key=EncryptedData(iv=None,
                                             ciphertext=VALUES['data_128'],
                                             tag=None))
     assert test == EncryptedDataKey(key_provider=MasterKeyInfo(
         provider_id=VALUES['provider_id'],
         key_info=VALUES['wrapped_keys']['raw']['key_info']),
                                     encrypted_data_key=VALUES['data_128'])
Example #13
0
 def test_serialize_wrapped_key_symmetric(self):
     test = aws_encryption_sdk.internal.formatting.serialize.serialize_wrapped_key(
         key_provider=self.mock_key_provider,
         wrapping_algorithm=self.mock_wrapping_algorithm,
         wrapping_key_id=VALUES['wrapped_keys']['raw']['key_info'],
         encrypted_wrapped_key=VALUES['wrapped_keys']['structures']
         ['wrapped_encrypted_data'])
     assert test == EncryptedDataKey(
         key_provider=MasterKeyInfo(
             provider_id=VALUES['provider_id'],
             key_info=VALUES['wrapped_keys']['serialized']['key_info']),
         encrypted_data_key=VALUES['wrapped_keys']['serialized']
         ['key_ciphertext'])
Example #14
0
 def test_serialize_wrapped_key_symmetric(self):
     test = aws_encryption_sdk.internal.formatting.serialize.serialize_wrapped_key(
         key_provider=self.mock_key_provider,
         wrapping_algorithm=self.mock_wrapping_algorithm,
         wrapping_key_id=VALUES["wrapped_keys"]["raw"]["key_info"],
         encrypted_wrapped_key=VALUES["wrapped_keys"]["structures"]
         ["wrapped_encrypted_data"],
     )
     assert test == EncryptedDataKey(
         key_provider=MasterKeyInfo(
             provider_id=VALUES["provider_id"],
             key_info=VALUES["wrapped_keys"]["serialized"]["key_info"]),
         encrypted_data_key=VALUES["wrapped_keys"]["serialized"]
         ["key_ciphertext"],
     )
def _do_aws_kms_encrypt(client_supplier, key_name, plaintext_data_key, encryption_context, grant_tokens):
    # type: (ClientSupplierType, str, RawDataKey, Dict[str, str], Iterable[str]) -> EncryptedDataKey
    """Attempt to call ``kms:Encrypt`` and return the resulting encrypted data key.

    Any errors encountered are passed up the chain without comment.
    """
    region = _region_from_key_id(key_name)
    client = client_supplier(region)
    response = client.encrypt(
        KeyId=key_name,
        Plaintext=plaintext_data_key.data_key,
        EncryptionContext=encryption_context,
        GrantTokens=grant_tokens,
    )
    return EncryptedDataKey(
        key_provider=MasterKeyInfo(provider_id=KEY_NAMESPACE, key_info=response["KeyId"]),
        encrypted_data_key=response["CiphertextBlob"],
    )
def _edk_cobinations():
    _edks = [
        EncryptedDataKey(key_provider=MasterKeyInfo(_PROVIDER_ID,
                                                    edk["key_info"]),
                         encrypted_data_key=edk["edk"])
        for edk in _ENCRYPTED_DATA_KEYS
    ]
    edks = itertools.permutations(_edks)

    mkps = [
        _keys_to_mkp(_keys) for _keys in itertools.chain.from_iterable([
            itertools.permutations(_ENCRYPTED_DATA_KEYS, i)
            for i in range(1,
                           len(_ENCRYPTED_DATA_KEYS) + 1)
        ])
    ]

    for edk_group, mkp_group in itertools.product(edks, mkps):
        yield mkp_group, edk_group
Example #17
0
def test_do_aws_kms_decrypt(fake_generator):
    encryption_context = {"foo": "bar"}
    kms = boto3.client("kms", region_name=FAKE_REGION)
    plaintext = b"0123" * 8
    response = kms.encrypt(KeyId=fake_generator, Plaintext=plaintext, EncryptionContext=encryption_context)

    encrypted_data_key = EncryptedDataKey(
        key_provider=MasterKeyInfo(provider_id=KEY_NAMESPACE, key_info=response["KeyId"]),
        encrypted_data_key=response["CiphertextBlob"],
    )

    decrypted_data_key = _do_aws_kms_decrypt(
        client_supplier=DefaultClientSupplier(),
        key_name=fake_generator,
        encrypted_data_key=encrypted_data_key,
        encryption_context=encryption_context,
        grant_tokens=[],
    )
    assert decrypted_data_key.data_key == plaintext
    def _encrypt_data_key(self, data_key, algorithm, encryption_context=None):
        """Encrypts a data key and returns the ciphertext.

        :param data_key: Unencrypted data key
        :type data_key: :class:`aws_encryption_sdk.structures.RawDataKey`
            or :class:`aws_encryption_sdk.structures.DataKey`
        :param algorithm: Placeholder to maintain API compatibility with parent
        :param dict encryption_context: Encryption context to pass to KMS
        :returns: Data key containing encrypted data key
        :rtype: aws_encryption_sdk.structures.EncryptedDataKey
        :raises EncryptKeyError: if Master Key is unable to encrypt data key
        """
        kms_params = self._build_encrypt_request(data_key, encryption_context)
        # Catch any boto3 errors and normalize to expected EncryptKeyError
        try:
            response = self.config.client.encrypt(**kms_params)
            # //= compliance/framework/aws-kms/aws-kms-mrk-aware-master-key.txt#2.11
            # //# The response's cipher text blob MUST be used as the "ciphertext" for the
            # //# encrypted data key.
            ciphertext = response["CiphertextBlob"]
            key_id = response["KeyId"]
        except (ClientError, KeyError):
            error_message = "Master Key {key_id} unable to encrypt data key".format(
                key_id=self._key_id)
            _LOGGER.exception(error_message)
            raise EncryptKeyError(error_message)

        # //= compliance/framework/aws-kms/aws-kms-mrk-aware-master-key.txt#2.11
        # //# The AWS KMS Encrypt response MUST contain a valid "KeyId".
        # arn_from_str will error if given an invalid key ARN
        try:
            key_id_str = to_str(key_id)
            arn_from_str(key_id_str)
        except MalformedArnError:
            error_message = "Retrieved an unexpected KeyID in response from KMS: {key_id}".format(
                key_id=key_id)
            _LOGGER.exception(error_message)
            raise EncryptKeyError(error_message)

        return EncryptedDataKey(key_provider=MasterKeyInfo(
            provider_id=self.provider_id, key_info=key_id),
                                encrypted_data_key=ciphertext)
 def setUp(self):
     self.mock_algorithm = MagicMock()
     self.mock_algorithm.__class__ = Algorithm
     self.mock_algorithm.data_key_len = sentinel.data_key_len
     self.mock_algorithm.kdf_input_len = sentinel.kdf_input_len
     self.mock_encrypted_data_key = EncryptedDataKey(
         key_provider=VALUES['key_provider'],
         encrypted_data_key=VALUES['encrypted_data_key'])
     self.mock_data_key = DataKey(
         key_provider=VALUES['key_provider'],
         data_key=VALUES['data_key'],
         encrypted_data_key=VALUES['encrypted_data_key'])
     self.mock_wrapping_algorithm = MagicMock()
     self.mock_wrapping_algorithm.__class__ = WrappingAlgorithm
     self.mock_wrapping_algorithm.encryption_type = sentinel.encryption_type
     self.mock_wrapping_key = MagicMock()
     self.mock_wrapping_key.__class__ = WrappingKey
     self.mock_wrapping_key.wrapping_algorithm = self.mock_wrapping_algorithm
     self.mock_wrapping_key.encrypt.return_value = sentinel.encrypted_data
     self.mock_wrapping_key.decrypt.return_value = VALUES['data_key']
def _do_aws_kms_generate_data_key(client_supplier, key_name, encryption_context, algorithm, grant_tokens):
    # type: (ClientSupplierType, str, Dict[str, str], AlgorithmSuite, Iterable[str]) -> (RawDataKey, EncryptedDataKey)
    """Attempt to call ``kms:GenerateDataKey`` and return the resulting plaintext and encrypted data keys.

    Any errors encountered are passed up the chain without comment.

    .. versionadded:: 1.5.0

    """
    region = _region_from_key_id(key_name)
    client = client_supplier(region)
    response = client.generate_data_key(
        KeyId=key_name,
        NumberOfBytes=algorithm.kdf_input_len,
        EncryptionContext=encryption_context,
        GrantTokens=grant_tokens,
    )
    provider = MasterKeyInfo(provider_id=KEY_NAMESPACE, key_info=response["KeyId"])
    plaintext_key = RawDataKey(key_provider=provider, data_key=response["Plaintext"])
    encrypted_key = EncryptedDataKey(key_provider=provider, encrypted_data_key=response["CiphertextBlob"])
    return plaintext_key, encrypted_key
Example #21
0
def test_aws_kms_discovery_keyring_on_decrypt_fail(caplog):
    # In this context there are no KMS CMKs, so any calls to KMS will fail.
    caplog.set_level(logging.DEBUG)
    keyring = _AwsKmsDiscoveryKeyring(client_supplier=DefaultClientSupplier())

    initial_materials = DecryptionMaterials(algorithm=ALGORITHM, encryption_context={},)

    result_materials = keyring.on_decrypt(
        decryption_materials=initial_materials,
        encrypted_data_keys=(
            EncryptedDataKey(
                key_provider=MasterKeyInfo(provider_id=KEY_NAMESPACE, key_info=b"bar"), encrypted_data_key=b"bar"
            ),
        ),
    )

    assert result_materials.data_encryption_key is None

    log_data = caplog.text
    # This means that it did actually try to decrypt the EDK but encountered an error talking to KMS.
    assert "Unable to decrypt encrypted data key from" in log_data
Example #22
0
def test_do_aws_kms_decrypt_unexpected_key_id(fake_generator_and_child):
    encryptor, decryptor = fake_generator_and_child
    encryption_context = {"foo": "bar"}
    kms = boto3.client("kms", region_name=FAKE_REGION)
    plaintext = b"0123" * 8
    response = kms.encrypt(KeyId=encryptor, Plaintext=plaintext, EncryptionContext=encryption_context)

    encrypted_data_key = EncryptedDataKey(
        key_provider=MasterKeyInfo(provider_id=KEY_NAMESPACE, key_info=response["KeyId"]),
        encrypted_data_key=response["CiphertextBlob"],
    )

    with pytest.raises(DecryptKeyError) as excinfo:
        _do_aws_kms_decrypt(
            client_supplier=DefaultClientSupplier(),
            key_name=decryptor,
            encrypted_data_key=encrypted_data_key,
            encryption_context=encryption_context,
            grant_tokens=[],
        )

    excinfo.match(r"Decryption results from AWS KMS are for an unexpected key ID*")
def prepare_data_keys(primary_master_key, master_keys, algorithm,
                      encryption_context):
    """Prepares a DataKey to be used for encrypting message and list
    of EncryptedDataKey objects to be serialized into header.

    :param primary_master_key: Master key with which to generate the encryption data key
    :type primary_master_key: aws_encryption_sdk.key_providers.base.MasterKey
    :param master_keys: All master keys with which to encrypt data keys
    :type master_keys: list of :class:`aws_encryption_sdk.key_providers.base.MasterKey`
    :param algorithm: Algorithm to use for encryption
    :type algorithm: aws_encryption_sdk.identifiers.Algorithm
    :param dict encryption_context: Encryption context to use when generating data key
    :rtype: tuple containing :class:`aws_encryption_sdk.structures.DataKey`
        and set of :class:`aws_encryption_sdk.structures.EncryptedDataKey`
    """
    encrypted_data_keys = set()
    encrypted_data_encryption_key = None
    data_encryption_key = primary_master_key.generate_data_key(
        algorithm, encryption_context)
    _LOGGER.debug('encryption data generated with master key: %s',
                  data_encryption_key.key_provider)
    for master_key in master_keys:
        # Don't re-encrypt the encryption data key; we already have the ciphertext
        if master_key is primary_master_key:
            encrypted_data_encryption_key = EncryptedDataKey(
                key_provider=data_encryption_key.key_provider,
                encrypted_data_key=data_encryption_key.encrypted_data_key)
            encrypted_data_keys.add(encrypted_data_encryption_key)
            continue
        encrypted_key = master_key.encrypt_data_key(
            data_key=data_encryption_key,
            algorithm=algorithm,
            encryption_context=encryption_context)
        encrypted_data_keys.add(encrypted_key)
        _LOGGER.debug('encryption key encrypted with master key: %s',
                      master_key.key_provider)
    return data_encryption_key, encrypted_data_keys
Example #24
0
def deserialize_header(stream):
    """Deserializes the header from a source stream

    :param stream: Source data stream
    :type stream: io.BytesIO
    :returns: Deserialized MessageHeader object
    :rtype: :class:`aws_encryption_sdk.structures.MessageHeader` and bytes
    :raises NotSupportedError: if unsupported data types are found
    :raises UnknownIdentityError: if unknown data types are found
    :raises SerializationError: if IV length does not match algorithm
    """
    _LOGGER.debug('Starting header deserialization')
    tee = io.BytesIO()
    tee_stream = TeeStream(stream, tee)
    version_id, message_type_id = unpack_values('>BB', tee_stream)
    try:
        message_type = ObjectType(message_type_id)
    except ValueError as error:
        raise NotSupportedError(
            'Unsupported type {} discovered in data stream'.format(
                message_type_id), error)
    try:
        version = SerializationVersion(version_id)
    except ValueError as error:
        raise NotSupportedError('Unsupported version {}'.format(version_id),
                                error)
    header = {'version': version, 'type': message_type}

    algorithm_id, message_id, ser_encryption_context_length = unpack_values(
        '>H16sH', tee_stream)

    try:
        alg = Algorithm.get_by_id(algorithm_id)
    except KeyError as error:
        raise UnknownIdentityError('Unknown algorithm {}'.format(algorithm_id),
                                   error)
    if not alg.allowed:
        raise NotSupportedError('Unsupported algorithm: {}'.format(alg))
    header['algorithm'] = alg
    header['message_id'] = message_id

    header['encryption_context'] = deserialize_encryption_context(
        tee_stream.read(ser_encryption_context_length))
    (encrypted_data_key_count, ) = unpack_values('>H', tee_stream)

    encrypted_data_keys = set([])
    for _ in range(encrypted_data_key_count):
        (key_provider_length, ) = unpack_values('>H', tee_stream)
        (key_provider_identifier, ) = unpack_values(
            '>{}s'.format(key_provider_length), tee_stream)
        (key_provider_information_length, ) = unpack_values('>H', tee_stream)
        (key_provider_information, ) = unpack_values(
            '>{}s'.format(key_provider_information_length), tee_stream)
        (encrypted_data_key_length, ) = unpack_values('>H', tee_stream)
        encrypted_data_key = tee_stream.read(encrypted_data_key_length)
        encrypted_data_keys.add(
            EncryptedDataKey(key_provider=MasterKeyInfo(
                provider_id=to_str(key_provider_identifier),
                key_info=key_provider_information),
                             encrypted_data_key=encrypted_data_key))
    header['encrypted_data_keys'] = encrypted_data_keys

    (content_type_id, ) = unpack_values('>B', tee_stream)
    try:
        content_type = ContentType(content_type_id)
    except ValueError as error:
        raise UnknownIdentityError(
            'Unknown content type {}'.format(content_type_id), error)
    header['content_type'] = content_type

    (content_aad_length, ) = unpack_values('>I', tee_stream)
    if content_aad_length != 0:
        raise SerializationError(
            'Content AAD length field is currently unused, its value must be always 0'
        )
    header['content_aad_length'] = 0

    (iv_length, ) = unpack_values('>B', tee_stream)
    if iv_length != alg.iv_len:
        raise SerializationError(
            'Specified IV length ({length}) does not match algorithm IV length ({alg})'
            .format(length=iv_length, alg=alg))
    header['header_iv_length'] = iv_length

    (frame_length, ) = unpack_values('>I', tee_stream)
    if content_type == ContentType.FRAMED_DATA and frame_length > MAX_FRAME_SIZE:
        raise SerializationError(
            'Specified frame length larger than allowed maximum: {found} > {max}'
            .format(found=frame_length, max=MAX_FRAME_SIZE))
    elif content_type == ContentType.NO_FRAMING and frame_length != 0:
        raise SerializationError(
            'Non-zero frame length found for non-framed message')
    header['frame_length'] = frame_length

    return MessageHeader(**header), tee.getvalue()
 def apply_fixtures(self):
     # Set up mock key provider and keys
     self.mock_key_provider_1 = MasterKeyInfo(provider_id="adijoasijfoi",
                                              key_info=b"asoiwef8q34")
     self.mock_raw_data_key_1_bytes = b"asioufhaw9eruhtg"
     self.mock_generated_data_key_1_bytes = b"df2hj9348r9824"
     self.mock_encrypted_data_key_1_bytes = b"asioufhaw9eruhtg"
     self.mock_raw_data_key_1 = RawDataKey(
         key_provider=self.mock_key_provider_1,
         data_key=self.mock_raw_data_key_1_bytes)
     self.mock_generated_data_key_1 = DataKey(
         key_provider=self.mock_key_provider_1,
         data_key=self.mock_generated_data_key_1_bytes,
         encrypted_data_key=self.mock_encrypted_data_key_1_bytes,
     )
     self.mock_encrypted_data_key_1 = EncryptedDataKey(
         key_provider=self.mock_key_provider_1,
         encrypted_data_key=self.mock_encrypted_data_key_1_bytes)
     self.mock_key_provider_2 = MasterKeyInfo(provider_id="9heui5349gh38",
                                              key_info=b"fj98349yhsfd")
     self.mock_raw_data_key_2_bytes = b"ane4856ht9w87y5"
     self.mock_generated_data_key_2_bytes = b"fih94587ty3t58yh5tg"
     self.mock_encrypted_data_key_2_bytes = b"ane4856ht9w87y5"
     self.mock_generated_data_key_2 = DataKey(
         key_provider=self.mock_key_provider_2,
         data_key=self.mock_generated_data_key_2_bytes,
         encrypted_data_key=self.mock_encrypted_data_key_2_bytes,
     )
     self.mock_encrypted_data_key_2 = EncryptedDataKey(
         key_provider=self.mock_key_provider_2,
         encrypted_data_key=self.mock_encrypted_data_key_2_bytes)
     self.mock_key_provider_3 = MasterKeyInfo(
         provider_id="sdfiwehjf9384u", key_info=b"evih5874yh587tyhu5")
     self.mock_raw_data_key_3_bytes = b"f839u459t83uh5rugh"
     self.mock_generated_data_key_3_bytes = b"sjhfuiehw498gfyu34098upoi"
     self.mock_encrypted_data_key_3_bytes = b"f839u459t83uh5rugh"
     self.mock_generated_data_key_3 = DataKey(
         key_provider=self.mock_key_provider_3,
         data_key=self.mock_generated_data_key_3_bytes,
         encrypted_data_key=self.mock_encrypted_data_key_3_bytes,
     )
     self.mock_encrypted_data_key_3 = EncryptedDataKey(
         key_provider=self.mock_key_provider_3,
         encrypted_data_key=self.mock_encrypted_data_key_3_bytes)
     self.mock_master_key_provider = MagicMock()
     self.mock_master_key_1 = MagicMock()
     self.mock_master_key_1.encrypt_data_key.return_value = self.mock_encrypted_data_key_1
     self.mock_master_key_1.generate_data_key.return_value = self.mock_generated_data_key_1
     self.mock_master_key_2 = MagicMock()
     self.mock_master_key_2.encrypt_data_key.return_value = self.mock_encrypted_data_key_2
     self.mock_master_key_2.generate_data_key.return_value = self.mock_generated_data_key_2
     self.mock_master_key_3 = MagicMock()
     self.mock_master_key_3.encrypt_data_key.return_value = self.mock_encrypted_data_key_3
     self.mock_master_key_3.generate_data_key.return_value = self.mock_generated_data_key_3
     self.mock_master_key_provider.master_keys_for_encryption.return_value = (
         self.mock_master_key_1,
         [
             self.mock_master_key_1, self.mock_master_key_2,
             self.mock_master_key_3
         ],
     )
     self.mock_decrypted_data_key_bytes = b"sehf98w34y987y9uierfh"
     self.mock_encrypted_data_key_bytes = b"sdhf4w398hfwea98ihfr0w8"
     self.mock_data_key = DataKey(
         key_provider=self.mock_key_provider_1,
         data_key=self.mock_decrypted_data_key_bytes,
         encrypted_data_key=self.mock_encrypted_data_key_bytes,
     )
     self.mock_encrypted_data_key = EncryptedDataKey(
         key_provider=self.mock_key_provider_1,
         encrypted_data_key=self.mock_encrypted_data_key_bytes)
     self.mock_decrypted_data_key = DataKey(
         key_provider=self.mock_key_provider_1,
         data_key=self.mock_decrypted_data_key_bytes,
         encrypted_data_key=self.mock_encrypted_data_key_1_bytes,
     )
     self.mock_master_key_provider.decrypt_data_key.return_value = self.mock_decrypted_data_key
     # Set up mock algorithm
     self.mock_algorithm = MagicMock()
     self.mock_algorithm.encryption_algorithm.block_size = VALUES[
         "block_size"]
     self.mock_algorithm.algorithm_id = VALUES["algorithm_id"]
     self.mock_algorithm.iv_len = VALUES["iv_len"]
     self.mock_algorithm.tag_len = self.mock_algorithm.auth_len = VALUES[
         "tag_len"]
     self.mock_algorithm.data_key_len = VALUES["data_key_len"]
     # Set up mock objects
     self.mock_bad_encrypted_key = MagicMock()
     self.mock_bad_encrypted_key.encrypted_data_key = sentinel.bad_encrypted_data_key
     self.mock_aws_encryption_sdk = MagicMock()
     # Set up os.urandom patch
     self.mock_urandom_patcher = patch(
         "aws_encryption_sdk.internal.utils.os.urandom")
     self.mock_urandom = self.mock_urandom_patcher.start()
     self.mock_urandom.return_value = sentinel.random
     # Set up KMSClient patch
     self.mock_aws_encryption_sdk_instance = MagicMock()
     self.mock_aws_encryption_sdk_instance.generate_data_key.return_value = (
         VALUES["data_key"],
         VALUES["encrypted_data_key"],
     )
     self.mock_aws_encryption_sdk_instance.decrypt.return_value = VALUES[
         "data_key"]
     self.mock_aws_encryption_sdk_instance.encrypt.return_value = VALUES[
         "encrypted_data_key"]
     yield
     # Run tearDown
     self.mock_urandom_patcher.stop()
Example #26
0
def test_encrypted_data_key_attributes_fails(key_provider, encrypted_data_key):
    with pytest.raises(TypeError):
        EncryptedDataKey(key_provider=key_provider,
                         encryted_data_key=encrypted_data_key)
Example #27
0
def test_Encrypted_data_key_attributes_succeeds():
    EncryptedDataKey(key_provider=MagicMock(__class__=MasterKeyInfo),
                     encrypted_data_key=b'')
    VALUES["final_frame_base"].tag,
])
VALUES["serialized_final_frame_bad_length"] = b"".join([
    b"\xff\xff\xff\xff",
    b"\x00\x00\x00\x01",
    VALUES["final_frame_base"].iv,
    struct.pack(">I", VALUES["small_frame_length"] + 1),
    VALUES["final_frame_base"].ciphertext,
    VALUES["final_frame_base"].tag,
])
VALUES["serialized_footer"] = b"".join(
    [VALUES["signature_len"], VALUES["signature"]])
VALUES["key_provider"] = MasterKeyInfo("aws-kms", VALUES["arn"])
VALUES["data_key_obj"] = DataKey(VALUES["key_provider"], VALUES["data_key"],
                                 VALUES["encrypted_data_key"])
VALUES["encrypted_data_key_obj"] = EncryptedDataKey(
    VALUES["key_provider"], VALUES["encrypted_data_key"])
VALUES["data_keys"] = [VALUES["data_key_obj"]]
VALUES["message_non_framed"] = b"".join([
    VALUES["header"], VALUES["header_auth"], VALUES["body_non_framed"],
    VALUES["footer"]
])
VALUES["message_single_frame"] = b"".join([
    VALUES["header"], VALUES["header_auth"], VALUES["body_final_frame"],
    VALUES["footer"]
])
VALUES["message_multi_frame"] = b"".join([
    VALUES["header"],
    VALUES["header_auth"],
    VALUES["body_frame"],
    VALUES["body_frame"],
    VALUES["body_final_frame"],
from ..unit_test_utils import (
    BrokenKeyring,
    NoEncryptedDataKeysKeyring,
    ephemeral_raw_aes_keyring,
    ephemeral_raw_aes_master_key,
)

pytestmark = [pytest.mark.unit, pytest.mark.local]

_DATA_KEY = DataKey(
    key_provider=MasterKeyInfo(provider_id="Provider", key_info=b"Info"),
    data_key=b"1234567890123456789012",
    encrypted_data_key=b"asdf",
)
_ENCRYPTED_DATA_KEY = EncryptedDataKey.from_data_key(_DATA_KEY)


@pytest.fixture
def patch_for_dcmm_encrypt(mocker):
    mocker.patch.object(DefaultCryptoMaterialsManager,
                        "_generate_signing_key_and_update_encryption_context")
    mock_signing_key = b"ex_signing_key"
    DefaultCryptoMaterialsManager._generate_signing_key_and_update_encryption_context.return_value = mock_signing_key
    mocker.patch.object(aws_encryption_sdk.materials_managers.default,
                        "prepare_data_keys")
    mock_data_encryption_key = _DATA_KEY
    mock_encrypted_data_keys = (_ENCRYPTED_DATA_KEY, )
    result_pair = mock_data_encryption_key, mock_encrypted_data_keys
    aws_encryption_sdk.materials_managers.default.prepare_data_keys.return_value = result_pair
    yield result_pair, mock_signing_key
 def setUp(self):
     # Set up mock key provider and keys
     self.mock_key_provider_1 = MasterKeyInfo(provider_id='adijoasijfoi',
                                              key_info=b'asoiwef8q34')
     self.mock_raw_data_key_1_bytes = b'asioufhaw9eruhtg'
     self.mock_generated_data_key_1_bytes = b'df2hj9348r9824'
     self.mock_encrypted_data_key_1_bytes = b'asioufhaw9eruhtg'
     self.mock_raw_data_key_1 = RawDataKey(
         key_provider=self.mock_key_provider_1,
         data_key=self.mock_raw_data_key_1_bytes)
     self.mock_generated_data_key_1 = DataKey(
         key_provider=self.mock_key_provider_1,
         data_key=self.mock_generated_data_key_1_bytes,
         encrypted_data_key=self.mock_encrypted_data_key_1_bytes)
     self.mock_encrypted_data_key_1 = EncryptedDataKey(
         key_provider=self.mock_key_provider_1,
         encrypted_data_key=self.mock_encrypted_data_key_1_bytes)
     self.mock_key_provider_2 = MasterKeyInfo(provider_id='9heui5349gh38',
                                              key_info=b'fj98349yhsfd')
     self.mock_raw_data_key_2_bytes = b'ane4856ht9w87y5'
     self.mock_generated_data_key_2_bytes = b'fih94587ty3t58yh5tg'
     self.mock_encrypted_data_key_2_bytes = b'ane4856ht9w87y5'
     self.mock_generated_data_key_2 = DataKey(
         key_provider=self.mock_key_provider_2,
         data_key=self.mock_generated_data_key_2_bytes,
         encrypted_data_key=self.mock_encrypted_data_key_2_bytes)
     self.mock_encrypted_data_key_2 = EncryptedDataKey(
         key_provider=self.mock_key_provider_2,
         encrypted_data_key=self.mock_encrypted_data_key_2_bytes)
     self.mock_key_provider_3 = MasterKeyInfo(
         provider_id='sdfiwehjf9384u', key_info=b'evih5874yh587tyhu5')
     self.mock_raw_data_key_3_bytes = b'f839u459t83uh5rugh'
     self.mock_generated_data_key_3_bytes = b'sjhfuiehw498gfyu34098upoi'
     self.mock_encrypted_data_key_3_bytes = b'f839u459t83uh5rugh'
     self.mock_generated_data_key_3 = DataKey(
         key_provider=self.mock_key_provider_3,
         data_key=self.mock_generated_data_key_3_bytes,
         encrypted_data_key=self.mock_encrypted_data_key_3_bytes)
     self.mock_encrypted_data_key_3 = EncryptedDataKey(
         key_provider=self.mock_key_provider_3,
         encrypted_data_key=self.mock_encrypted_data_key_3_bytes)
     self.mock_master_key_provider = MagicMock()
     self.mock_master_key_1 = MagicMock()
     self.mock_master_key_1.encrypt_data_key.return_value = self.mock_encrypted_data_key_1
     self.mock_master_key_1.generate_data_key.return_value = self.mock_generated_data_key_1
     self.mock_master_key_2 = MagicMock()
     self.mock_master_key_2.encrypt_data_key.return_value = self.mock_encrypted_data_key_2
     self.mock_master_key_2.generate_data_key.return_value = self.mock_generated_data_key_2
     self.mock_master_key_3 = MagicMock()
     self.mock_master_key_3.encrypt_data_key.return_value = self.mock_encrypted_data_key_3
     self.mock_master_key_3.generate_data_key.return_value = self.mock_generated_data_key_3
     self.mock_master_key_provider.master_keys_for_encryption.return_value = (
         self.mock_master_key_1, [
             self.mock_master_key_1, self.mock_master_key_2,
             self.mock_master_key_3
         ])
     self.mock_decrypted_data_key_bytes = b'sehf98w34y987y9uierfh'
     self.mock_encrypted_data_key_bytes = b'sdhf4w398hfwea98ihfr0w8'
     self.mock_data_key = DataKey(
         key_provider=self.mock_key_provider_1,
         data_key=self.mock_decrypted_data_key_bytes,
         encrypted_data_key=self.mock_encrypted_data_key_bytes)
     self.mock_encrypted_data_key = EncryptedDataKey(
         key_provider=self.mock_key_provider_1,
         encrypted_data_key=self.mock_encrypted_data_key_bytes)
     self.mock_decrypted_data_key = DataKey(
         key_provider=self.mock_key_provider_1,
         data_key=self.mock_decrypted_data_key_bytes,
         encrypted_data_key=self.mock_encrypted_data_key_1_bytes)
     self.mock_master_key_provider.decrypt_data_key.return_value = self.mock_decrypted_data_key
     # Set up mock algorithm
     self.mock_algorithm = MagicMock()
     self.mock_algorithm.encryption_algorithm.block_size = VALUES[
         'block_size']
     self.mock_algorithm.algorithm_id = VALUES['algorithm_id']
     self.mock_algorithm.iv_len = VALUES['iv_len']
     self.mock_algorithm.tag_len = self.mock_algorithm.auth_len = VALUES[
         'tag_len']
     self.mock_algorithm.data_key_len = VALUES['data_key_len']
     # Set up mock objects
     self.mock_bad_encrypted_key = MagicMock()
     self.mock_bad_encrypted_key.encrypted_data_key = sentinel.bad_encrypted_data_key
     self.mock_aws_encryption_sdk = MagicMock()
     # Set up os.urandom patch
     self.mock_urandom_patcher = patch(
         'aws_encryption_sdk.internal.utils.os.urandom')
     self.mock_urandom = self.mock_urandom_patcher.start()
     self.mock_urandom.return_value = sentinel.random
     # Set up KMSClient patch
     self.mock_aws_encryption_sdk_instance = MagicMock()
     self.mock_aws_encryption_sdk_instance.generate_data_key.return_value = (
         VALUES['data_key'], VALUES['encrypted_data_key'])
     self.mock_aws_encryption_sdk_instance.decrypt.return_value = VALUES[
         'data_key']
     self.mock_aws_encryption_sdk_instance.encrypt.return_value = VALUES[
         'encrypted_data_key']