def _prep_message(self): """Performs initial message setup. :raises MasterKeyProviderError: if primary master key is not a member of supplied MasterKeyProvider :raises MasterKeyProviderError: if no Master Keys are returned from key_provider """ validate_commitment_policy_on_encrypt(self.config.commitment_policy, self.config.algorithm) try: plaintext_length = self.stream_length except NotSupportedError: plaintext_length = None encryption_materials_request = EncryptionMaterialsRequest( algorithm=self.config.algorithm, encryption_context=self.config.encryption_context.copy(), frame_length=self.config.frame_length, plaintext_rostream=aws_encryption_sdk.internal.utils.streams. ROStream(self.source_stream), plaintext_length=plaintext_length, commitment_policy=self.config.commitment_policy, ) self._encryption_materials = self.config.materials_manager.get_encryption_materials( request=encryption_materials_request) if self.config.algorithm is not None and self._encryption_materials.algorithm != self.config.algorithm: raise ActionNotAllowedError( ("Cryptographic materials manager provided algorithm suite" " differs from algorithm suite in request.\n" "Required: {requested}\n" "Provided: {provided}").format( requested=self.config.algorithm, provided=self._encryption_materials.algorithm)) if self._encryption_materials.signing_key is None: self.signer = None else: self.signer = Signer.from_key_bytes( algorithm=self._encryption_materials.algorithm, key_bytes=self._encryption_materials.signing_key) aws_encryption_sdk.internal.utils.validate_frame_length( frame_length=self.config.frame_length, algorithm=self._encryption_materials.algorithm) message_id = aws_encryption_sdk.internal.utils.message_id( self._encryption_materials.algorithm.message_id_length()) self._derived_data_key = derive_data_encryption_key( source_key=self._encryption_materials.data_encryption_key.data_key, algorithm=self._encryption_materials.algorithm, message_id=message_id, ) self._header = self.generate_header(message_id) self._write_header() if self.content_type == ContentType.NO_FRAMING: self._prep_non_framed() self._message_prepped = True
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 = aws_encryption_sdk.internal.formatting.deserialize.deserialize_header(self.source_stream) 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} > {custom}'.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 ) 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 = aws_encryption_sdk.internal.formatting.deserialize.deserialize_header_auth( 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 ) aws_encryption_sdk.internal.formatting.deserialize.validate_header( header=header, header_auth=header_auth, raw_header=raw_header, data_key=self._derived_data_key ) return header, header_auth
def test_derive_data_encryption_key_with_hkdf(patch_default_backend, patch_struct): algorithm = MagicMock() algorithm.kdf_hash_type.return_value = sentinel.kdf_hash_type test = derive_data_encryption_key( source_key=sentinel.source_key, algorithm=algorithm, message_id=sentinel.message_id ) patch_struct.pack.assert_called_with(">H16s", algorithm.algorithm_id, sentinel.message_id) algorithm.kdf_type.assert_called_with( algorithm=sentinel.kdf_hash_type, length=algorithm.data_key_len, salt=None, info=patch_struct.pack.return_value, backend=patch_default_backend.return_value, ) algorithm.kdf_type.return_value.derive.assert_called_with(sentinel.source_key) assert test == algorithm.kdf_type.return_value.derive.return_value
def test_derive_data_encryption_key_with_hkdf_committing(patch_default_backend, patch_struct): algorithm = MagicMock() algorithm.kdf_hash_type.return_value = sentinel.kdf_hash_type algorithm.data_key_len = sentinel.data_key_len algorithm.is_committing.return_value = True test = data_keys.derive_data_encryption_key( source_key=sentinel.source_key, algorithm=algorithm, message_id=sentinel.message_id ) patch_struct.pack.assert_called_with(">H9s", algorithm.algorithm_id, data_keys.KEY_LABEL) algorithm.kdf_type.assert_called_with( algorithm=sentinel.kdf_hash_type, length=sentinel.data_key_len, salt=sentinel.message_id, info=patch_struct.pack.return_value, backend=patch_default_backend.return_value, ) algorithm.kdf_type.return_value.derive.assert_called_with(sentinel.source_key) assert test == algorithm.kdf_type.return_value.derive.return_value
def test_derive_data_encryption_key_no_hkdf(): algorithm = MagicMock(kdf_type=None) test = data_keys.derive_data_encryption_key(source_key=sentinel.source_key, algorithm=algorithm, message_id=sentinel.message_id) assert test == sentinel.source_key
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