Exemplo n.º 1
0
    def _generate_data_key(self, algorithm, encryption_context=None):
        """Generates data key and returns plaintext and ciphertext of key.

        :param algorithm: Algorithm on which to base data key
        :type algorithm: aws_encryption_sdk.identifiers.Algorithm
        :param dict encryption_context: Encryption context to pass to KMS
        :returns: Generated data key
        :rtype: aws_encryption_sdk.structures.DataKey
        """
        kms_params = {
            "KeyId": self._key_id,
            "NumberOfBytes": algorithm.kdf_input_len
        }
        if encryption_context is not None:
            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.generate_data_key(**kms_params)
            plaintext = response["Plaintext"]
            ciphertext = response["CiphertextBlob"]
            key_id = response["KeyId"]
        except (ClientError, KeyError):
            error_message = "Master Key {key_id} unable to generate data key".format(
                key_id=self._key_id)
            _LOGGER.exception(error_message)
            raise GenerateKeyError(error_message)
        return DataKey(
            key_provider=MasterKeyInfo(provider_id=self.provider_id,
                                       key_info=key_id),
            data_key=plaintext,
            encrypted_data_key=ciphertext,
        )
Exemplo n.º 2
0
def _generate_data_key(
        encryption_materials,  # type: EncryptionMaterials
        key_provider,  # type: MasterKeyInfo
):
    # type: (...) -> EncryptionMaterials
    """Generates plaintext data key for the keyring.

    :param EncryptionMaterials encryption_materials: Encryption materials for the keyring to modify.
    :param MasterKeyInfo key_provider: Information about the key in the keyring.
    :rtype: EncryptionMaterials
    :returns: Encryption materials containing a data encryption key
    """
    # Check if encryption materials contain data encryption key
    if encryption_materials.data_encryption_key is not None:
        raise TypeError("Data encryption key already exists.")

    # Generate data key
    try:
        plaintext_data_key = os.urandom(
            encryption_materials.algorithm.kdf_input_len)
    except Exception:  # pylint: disable=broad-except
        error_message = "Unable to generate data encryption key."
        _LOGGER.exception(error_message)
        raise GenerateKeyError("Unable to generate data encryption key.")

    # Create a keyring trace
    keyring_trace = KeyringTrace(wrapping_key=key_provider,
                                 flags={KeyringTraceFlag.GENERATED_DATA_KEY})

    # plaintext_data_key to RawDataKey
    data_encryption_key = RawDataKey(key_provider=key_provider,
                                     data_key=plaintext_data_key)

    return encryption_materials.with_data_encryption_key(
        data_encryption_key=data_encryption_key, keyring_trace=keyring_trace)
Exemplo n.º 3
0
    def on_encrypt(self, encryption_materials):
        # type: (EncryptionMaterials) -> EncryptionMaterials
        """Generate a data key using generator keyring
        and encrypt it using any available wrapping key in any child keyring.

        :param EncryptionMaterials encryption_materials: Encryption materials for keyring to modify.
        :returns: Optionally modified encryption materials.
        :rtype: EncryptionMaterials
        :raises EncryptKeyError: if unable to encrypt data key.
        """
        # Check if generator keyring is not provided and data key is not generated
        if self.generator is None and encryption_materials.data_encryption_key is None:
            raise EncryptKeyError(
                "Generator keyring not provided "
                "and encryption materials do not already contain a plaintext data key."
            )

        new_materials = encryption_materials

        # Call on_encrypt on the generator keyring if it is provided
        if self.generator is not None:
            new_materials = self.generator.on_encrypt(
                encryption_materials=new_materials)

        # Check if data key is generated
        if new_materials.data_encryption_key is None:
            raise GenerateKeyError("Unable to generate data encryption key.")

        # Call on_encrypt on all other keyrings
        for keyring in self.children:
            new_materials = keyring.on_encrypt(
                encryption_materials=new_materials)

        return new_materials
Exemplo n.º 4
0
    def _generate_data_key(self, algorithm, encryption_context=None):
        """Generates data key and returns plaintext and ciphertext of key.

        :param algorithm: Algorithm on which to base data key
        :type algorithm: aws_encryption_sdk.identifiers.Algorithm
        :param dict encryption_context: Encryption context to pass to KMS
        :returns: Generated data key
        :rtype: aws_encryption_sdk.structures.DataKey
        """
        kms_params = self._build_generate_data_key_request(
            algorithm, encryption_context)
        # Catch any boto3 errors and normalize to expected EncryptKeyError
        try:
            response = self.config.client.generate_data_key(**kms_params)
            # //= compliance/framework/aws-kms/aws-kms-mrk-aware-master-key.txt#2.10
            # //# The response's "Plaintext" MUST be the plaintext in the output.
            plaintext = response["Plaintext"]
            # //= compliance/framework/aws-kms/aws-kms-mrk-aware-master-key.txt#2.10
            # //# The response's cipher text blob MUST be used as the returned as the
            # //# ciphertext for the encrypted data key in the output.
            ciphertext = response["CiphertextBlob"]
            key_id = response["KeyId"]
        except (ClientError, KeyError):
            error_message = "Master Key {key_id} unable to generate data key".format(
                key_id=self._key_id)
            _LOGGER.exception(error_message)
            raise GenerateKeyError(error_message)

        # //= compliance/framework/aws-kms/aws-kms-mrk-aware-master-key.txt#2.10
        # //# The response's "KeyId" MUST be valid.
        # 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 GenerateKeyError(error_message)

        return DataKey(
            key_provider=MasterKeyInfo(provider_id=self.provider_id,
                                       key_info=key_id),
            data_key=plaintext,
            encrypted_data_key=ciphertext,
        )