Пример #1
0
    def master_keys_for_encryption(self, encryption_context, plaintext_rostream, plaintext_length=None):
        """Returns a set containing all Master Keys added to this Provider, or any member Providers,
        which should be used to encrypt data keys for the specified data.

        .. note::
            This does not necessarily include all Master Keys accessible from this Provider.

        .. note::
            The Primary Master Key is the first Master Key added to this Master Key Provider
            and is the Master Key which will be used to generate the data key.

        .. warning::
            If plaintext_rostream seek position is modified, it must be returned before leaving method.

        :param dict encryption_context: Encryption context passed to client
        :param plaintext_rostream: Source plaintext read-only stream
        :type plaintext_rostream: aws_encryption_sdk.internal.utils.streams.ROStream
        :param int plaintext_length: Length of source plaintext (optional)
        :returns: Tuple containing Primary Master Key and List of all Master Keys added to
            this Provider and any member Providers
        :rtype: tuple containing :class:`aws_encryption_sdk.key_providers.base.MasterKey`
            and list of :class:`aws_encryption_sdk.key_providers.base.MasterKey`
        """
        primary = None
        master_keys = []
        for member_provider in self._members:
            _primary, _master_keys = member_provider.master_keys_for_encryption(
                encryption_context, plaintext_rostream, plaintext_length
            )
            if primary is None:
                primary = _primary
            master_keys.extend(_master_keys)
        if not master_keys:
            raise MasterKeyProviderError("No Master Keys available from Master Key Provider")
        return primary, master_keys
Пример #2
0
    def _new_master_key(self, key_id):
        """Returns a KMSMasterKey for the specified key_id.

        :param bytes key_id: KMS CMK ID
        :returns: KMS Master Key based on key_id
        :rtype: aws_encryption_sdk.key_providers.kms.KMSMasterKey
        :raises InvalidKeyIdError: if key_id is not a valid KMS CMK ID to which this key provider has access
        :raises MasterKeyProviderError: if this MasterKeyProvider is in discovery mode and key_id is not allowed
        """
        _key_id = to_str(key_id)  # KMS client requires str, not bytes

        if self.config.discovery_filter:
            arn = arn_from_str(_key_id)

            if (arn.partition != self.config.discovery_filter.partition
                    or arn.account_id
                    not in self.config.discovery_filter.account_ids):
                # //= compliance/framework/aws-kms/aws-kms-mrk-aware-master-key-provider.txt#2.7
                # //# In discovery mode if a discovery filter is configured the requested AWS
                # //# KMS key ARN's "partition" MUST match the discovery filter's
                # //# "partition" and the AWS KMS key ARN's "account" MUST exist in the
                # //# discovery filter's account id set.
                raise MasterKeyProviderError(
                    "Key {} not allowed by this Master Key Provider".format(
                        key_id))
        return self._new_master_key_impl(key_id)
    def _get_encryption_materials_using_master_key_provider(self, request):
        """Creates encryption materials using underlying master key provider.

        :param request: encryption materials request
        :type request: aws_encryption_sdk.materials_managers.EncryptionMaterialsRequest
        :returns: encryption materials
        :rtype: aws_encryption_sdk.materials_managers.EncryptionMaterials
        :raises MasterKeyProviderError: if no master keys are available from the underlying master key provider
        :raises MasterKeyProviderError: if the primary master key provided by the underlying master key provider
            is not included in the full set of master keys provided by that provider
        """
        algorithm = request.algorithm if request.algorithm is not None else self.algorithm
        encryption_context = request.encryption_context.copy()

        signing_key = self._generate_signing_key_and_update_encryption_context(
            algorithm, encryption_context)

        primary_master_key, master_keys = self.master_key_provider.master_keys_for_encryption(
            encryption_context=encryption_context,
            plaintext_rostream=request.plaintext_rostream,
            plaintext_length=request.plaintext_length,
        )
        if not master_keys:
            raise MasterKeyProviderError(
                "No Master Keys available from Master Key Provider")
        if primary_master_key not in master_keys:
            raise MasterKeyProviderError(
                "Primary Master Key not in provided Master Keys")

        data_encryption_key, encrypted_data_keys = prepare_data_keys(
            primary_master_key=primary_master_key,
            master_keys=master_keys,
            algorithm=algorithm,
            encryption_context=encryption_context,
        )

        _LOGGER.debug("Post-encrypt encryption context: %s",
                      encryption_context)

        return EncryptionMaterials(
            algorithm=algorithm,
            data_encryption_key=data_encryption_key,
            encrypted_data_keys=encrypted_data_keys,
            encryption_context=encryption_context,
            signing_key=signing_key,
        )
Пример #4
0
    def _new_master_key(self, key_id):
        """Returns a KMSMasterKey for the specified key_id.

        :param bytes key_id: KMS CMK ID
        :returns: KMS Master Key based on key_id
        :rtype: aws_encryption_sdk.key_providers.kms.KMSMasterKey
        :raises InvalidKeyIdError: if key_id is not a valid KMS CMK ID to which this key provider has access
        :raises MasterKeyProviderError: if this MasterKeyProvider is in discovery mode and key_id is not allowed
        """
        _key_id = to_str(key_id)  # KMS client requires str, not bytes

        if self.config.discovery_filter:
            arn = arn_from_str(_key_id)

            if (arn.partition != self.config.discovery_filter.partition
                    or arn.account_id
                    not in self.config.discovery_filter.account_ids):
                raise MasterKeyProviderError(
                    "Key {} not allowed by this Master Key Provider".format(
                        key_id))

        return KMSMasterKey(config=KMSMasterKeyConfig(
            key_id=key_id, client=self._client(_key_id)))
Пример #5
0
def prepare_data_keys(key_provider,
                      algorithm,
                      encryption_context,
                      plaintext_rostream,
                      plaintext_length=None,
                      data_key=None):
    """Prepares a DataKey to be used for encrypting message and list
    of EncryptedDataKey objects to be serialized into header.

    :param key_provider: Master Key Provider to use
    :type key_provider: aws_encryption_sdk.key_providers.base.MasterKeyProvider
    :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
    :param plaintext_stream: Source plaintext read-only stream
    :type plaintext_rostream: aws_encryption_sdk.internal.utils.ROStream
    :param int plaintext_length: Length of source plaintext (optional)
    :param data_key: Object containing data key to use (if not supplied, a new key will be generated)
    :type data_key: :class:`aws_encryption_sdk.structure.DataKey`
        or :class:`aws_encryption_sdk.structure.RawDataKey`
    :rtype: tuple containing :class:`aws_encryption_sdk.structure.RawDataKey`
        and set of :class:`aws_encryption_sdk.structure.EncryptedDataKey`
    :raises SerializationError: if primary master key is not a member of supplied MasterKeyProvider
    :raises NotSupportedError: if data_key is not a supported data type
    :raises MasterKeyProviderError: if no Master Keys are returned from key_provider
    """
    primary_master_key, master_keys = key_provider.master_keys_for_encryption(
        encryption_context=encryption_context,
        plaintext_rostream=plaintext_rostream,
        plaintext_length=plaintext_length)
    if not master_keys:
        raise MasterKeyProviderError(
            'No Master Keys available from Master Key Provider')
    if primary_master_key not in master_keys:
        raise MasterKeyProviderError(
            'Primary Master Key not in provided Master Keys')
    encrypted_data_keys = set()
    encrypted_encryption_data_key = None
    if not data_key:
        encryption_data_key = primary_master_key.generate_data_key(
            algorithm, encryption_context)
        _LOGGER.debug('encryption data key generated from primary master key')
    elif isinstance(data_key, RawDataKey):
        encryption_data_key = data_key
        _LOGGER.debug('raw encryption data key provided')
    elif isinstance(data_key, DataKey):
        encryption_data_key = data_key
        _LOGGER.debug('full encryption data key provided')
    else:
        raise NotSupportedError('Unsupported data_key type: {}'.format(
            type(data_key)))
    _LOGGER.debug('encryption data key provider: %s',
                  encryption_data_key.key_provider)
    for master_key in master_keys:
        encrypted_key = master_key.encrypt_data_key(
            data_key=encryption_data_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)
        if master_key is primary_master_key:
            encrypted_encryption_data_key = encrypted_key
    # Normalize output to DataKey
    encryption_data_key = DataKey(
        key_provider=encryption_data_key.key_provider,
        data_key=encryption_data_key.data_key,
        encrypted_data_key=encrypted_encryption_data_key.encrypted_data_key)
    return encryption_data_key, encrypted_data_keys
Пример #6
0
    def _read_header(self):
        """Reads the message header from the input stream.

        :returns: tuple containing deserialized header and header_auth objects
        :rtype: tuple of aws_encryption_sdk.structures.MessageHeader
            and aws_encryption_sdk.internal.structures.MessageHeaderAuthentication
        :raises CustomMaximumValueExceeded: if frame length is greater than the custom max value
        """
        header, raw_header = deserialize_header(self.source_stream)
        self.__unframed_bytes_read += len(raw_header)

        validate_commitment_policy_on_decrypt(self.config.commitment_policy,
                                              header.algorithm)

        if (self.config.max_body_length is not None
                and header.content_type == ContentType.FRAMED_DATA
                and header.frame_length > self.config.max_body_length):
            raise CustomMaximumValueExceeded(
                "Frame Size in header found larger than custom value: {found:d} > {custom:d}"
                .format(found=header.frame_length,
                        custom=self.config.max_body_length))

        decrypt_materials_request = DecryptionMaterialsRequest(
            encrypted_data_keys=header.encrypted_data_keys,
            algorithm=header.algorithm,
            encryption_context=header.encryption_context,
            commitment_policy=self.config.commitment_policy,
        )
        decryption_materials = self.config.materials_manager.decrypt_materials(
            request=decrypt_materials_request)
        if decryption_materials.verification_key is None:
            self.verifier = None
        else:
            self.verifier = Verifier.from_key_bytes(
                algorithm=header.algorithm,
                key_bytes=decryption_materials.verification_key)
        if self.verifier is not None:
            self.verifier.update(raw_header)

        header_auth = deserialize_header_auth(version=header.version,
                                              stream=self.source_stream,
                                              algorithm=header.algorithm,
                                              verifier=self.verifier)
        self._derived_data_key = derive_data_encryption_key(
            source_key=decryption_materials.data_key.data_key,
            algorithm=header.algorithm,
            message_id=header.message_id)

        if header.algorithm.is_committing():
            expected_commitment_key = calculate_commitment_key(
                source_key=decryption_materials.data_key.data_key,
                algorithm=header.algorithm,
                message_id=header.message_id,
            )

            if not hmac.compare_digest(expected_commitment_key,
                                       header.commitment_key):
                raise MasterKeyProviderError(
                    "Key commitment validation failed. Key identity does not match the identity asserted in the "
                    "message. Halting processing of this message.")

        validate_header(header=header,
                        header_auth=header_auth,
                        raw_header=raw_header,
                        data_key=self._derived_data_key)

        return header, header_auth