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
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)
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
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)
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
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 ])
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, )
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'])
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'])
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 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
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
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
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
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()
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)
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']