def test_validate_encryption(self): # Arrange queue_name = self._create_queue() kek = KeyWrapper('key1') self.qs.key_encryption_key = kek self.qs.put_message(queue_name, u'message') # Act self.qs.key_encryption_key = None # Message will not be decrypted li = self.qs.peek_messages(queue_name) message = li[0].content message = loads(message) encryption_data = message['EncryptionData'] wrapped_content_key = encryption_data['WrappedContentKey'] wrapped_content_key = _WrappedContentKey( wrapped_content_key['Algorithm'], b64decode( wrapped_content_key['EncryptedKey'].encode(encoding='utf-8')), wrapped_content_key['KeyId']) encryption_agent = encryption_data['EncryptionAgent'] encryption_agent = _EncryptionAgent( encryption_agent['EncryptionAlgorithm'], encryption_agent['Protocol']) encryption_data = _EncryptionData( b64decode(encryption_data['ContentEncryptionIV'].encode( encoding='utf-8')), encryption_agent, wrapped_content_key, {'EncryptionLibrary': __version__}) message = message['EncryptedMessageContents'] content_encryption_key = kek.unwrap_key( encryption_data.wrapped_content_key.encrypted_key, encryption_data.wrapped_content_key.algorithm) # Create decryption cipher backend = backends.default_backend() algorithm = AES(content_encryption_key) mode = CBC(encryption_data.content_encryption_IV) cipher = Cipher(algorithm, mode, backend) # decode and decrypt data decrypted_data = _decode_base64_to_bytes(message) decryptor = cipher.decryptor() decrypted_data = (decryptor.update(decrypted_data) + decryptor.finalize()) # unpad data unpadder = PKCS7(128).unpadder() decrypted_data = (unpadder.update(decrypted_data) + unpadder.finalize()) decrypted_data = decrypted_data.decode(encoding='utf-8') # Assert self.assertEqual(decrypted_data, u'message')
def test_validate_encryption(self): # Arrange queue_name = self._create_queue() kek = KeyWrapper('key1') self.qs.key_encryption_key = kek self.qs.put_message(queue_name, u'message') # Act self.qs.key_encryption_key = None # Message will not be decrypted li = self.qs.peek_messages(queue_name) message = li[0].content message = loads(message) encryption_data = message['EncryptionData'] wrapped_content_key = encryption_data['WrappedContentKey'] wrapped_content_key = _WrappedContentKey(wrapped_content_key['Algorithm'], b64decode( wrapped_content_key['EncryptedKey'].encode(encoding='utf-8')), wrapped_content_key['KeyId']) encryption_agent = encryption_data['EncryptionAgent'] encryption_agent = _EncryptionAgent(encryption_agent['EncryptionAlgorithm'], encryption_agent['Protocol']) encryption_data = _EncryptionData(b64decode(encryption_data['ContentEncryptionIV'].encode(encoding='utf-8')), encryption_agent, wrapped_content_key, {'EncryptionLibrary': __version__}) message = message['EncryptedMessageContents'] content_encryption_key = kek.unwrap_key(encryption_data.wrapped_content_key.encrypted_key, encryption_data.wrapped_content_key.algorithm) # Create decryption cipher backend = backends.default_backend() algorithm = AES(content_encryption_key) mode = CBC(encryption_data.content_encryption_IV) cipher = Cipher(algorithm, mode, backend) # decode and decrypt data decrypted_data = _decode_base64_to_bytes(message) decryptor = cipher.decryptor() decrypted_data = (decryptor.update(decrypted_data) + decryptor.finalize()) # unpad data unpadder = PKCS7(128).unpadder() decrypted_data = (unpadder.update(decrypted_data) + unpadder.finalize()) decrypted_data = decrypted_data.decode(encoding='utf-8') # Assert self.assertEqual(decrypted_data, u'message')
def _decrypt_queue_message(message, require_encryption, key_encryption_key, resolver): ''' Returns the decrypted message contents from an EncryptedQueueMessage. If no encryption metadata is present, will return the unaltered message. :param str message: The JSON formatted QueueEncryptedMessage contents with all associated metadata. :param bool require_encryption: If set, will enforce that the retrieved messages are encrypted and decrypt them. :param object key_encryption_key: The user-provided key-encryption-key. Must implement the following methods: unwrap_key(key, algorithm)--returns the unwrapped form of the specified symmetric key using the string-specified algorithm. get_kid()--returns a string key id for this key-encryption-key. :param function resolver(kid): The user-provided key resolver. Uses the kid string to return a key-encryption-key implementing the interface defined above. :return: The plain text message from the queue message. :rtype: str ''' try: message = loads(message) encryption_data = _dict_to_encryption_data(message['EncryptionData']) decoded_data = _decode_base64_to_bytes( message['EncryptedMessageContents']) except (KeyError, ValueError): # Message was not json formatted and so was not encrypted # or the user provided a json formatted message. if require_encryption: raise ValueError(_ERROR_MESSAGE_NOT_ENCRYPTED) else: return message try: return _decrypt(decoded_data, encryption_data, key_encryption_key, resolver).decode('utf-8') except Exception: raise AzureException(_ERROR_DECRYPTION_FAILURE)
def _from_entity_binary(value): return EntityProperty(EdmType.BINARY, _decode_base64_to_bytes(value))
def _from_entity_binary(value): return EntityProperty(EdmType.BINARY, _decode_base64_to_bytes(value))
def _extract_encryption_metadata(entity, require_encryption, key_encryption_key, key_resolver): ''' Extracts the encryption metadata from the given entity, setting them to be utf-8 strings. If no encryption metadata is present, will return None for all return values unless require_encryption is true, in which case the method will throw. :param entity: The entity being retrieved and decrypted. Could be a dict or an entity object. :param bool require_encryption: If set, will enforce that the retrieved entity is encrypted and decrypt it. :param object key_encryption_key: The user-provided key-encryption-key. Must implement the following methods: unwrap_key(key, algorithm)--returns the unwrapped form of the specified symmetric key using the string-specified algorithm. get_kid()--returns a string key id for this key-encryption-key. :param function key_resolver(kid): The user-provided key resolver. Uses the kid string to return a key-encryption-key implementing the interface defined above. :returns: a tuple containing the entity iv, the list of encrypted properties, the entity cek, and whether the entity was encrypted using JavaV1. :rtype: tuple (bytes[], list, bytes[], bool) ''' _validate_not_none('entity', entity) try: encrypted_properties_list = _decode_base64_to_bytes(entity['_ClientEncryptionMetadata2']) encryption_data = entity['_ClientEncryptionMetadata1'] encryption_data = _dict_to_encryption_data(loads(encryption_data)) except Exception: # Message did not have properly formatted encryption metadata. if require_encryption: raise ValueError(_ERROR_ENTITY_NOT_ENCRYPTED) else: return None, None, None, None if not (encryption_data.encryption_agent.encryption_algorithm == _EncryptionAlgorithm.AES_CBC_256): raise ValueError(_ERROR_UNSUPPORTED_ENCRYPTION_ALGORITHM) content_encryption_key = _validate_and_unwrap_cek(encryption_data, key_encryption_key, key_resolver) # Special check for compatibility with Java V1 encryption protocol. isJavaV1 = (encryption_data.key_wrapping_metadata is None) or \ ((encryption_data.encryption_agent.protocol == _ENCRYPTION_PROTOCOL_V1) and 'EncryptionLibrary' in encryption_data.key_wrapping_metadata and 'Java' in encryption_data.key_wrapping_metadata['EncryptionLibrary']) metadataIV = _generate_property_iv(encryption_data.content_encryption_IV, entity['PartitionKey'], entity['RowKey'], '_ClientEncryptionMetadata2', isJavaV1) cipher = _generate_AES_CBC_cipher(content_encryption_key, metadataIV) # Decrypt the data. decryptor = cipher.decryptor() encrypted_properties_list = decryptor.update(encrypted_properties_list) + decryptor.finalize() # Unpad the data. unpadder = PKCS7(128).unpadder() encrypted_properties_list = unpadder.update(encrypted_properties_list) + unpadder.finalize() encrypted_properties_list = encrypted_properties_list.decode('utf-8') if isJavaV1: # Strip the square braces from the ends and split string into list. encrypted_properties_list = encrypted_properties_list[1:-1] encrypted_properties_list = encrypted_properties_list.split(', ') else: encrypted_properties_list = loads(encrypted_properties_list) return encryption_data.content_encryption_IV, encrypted_properties_list, content_encryption_key, isJavaV1