def decrypt_blob(  # pylint: disable=too-many-locals,too-many-statements
        require_encryption,
        key_encryption_key,
        key_resolver,
        content,
        start_offset,
        end_offset,
        response_headers):
    """
    Decrypts the given blob contents and returns only the requested range.

    :param bool require_encryption:
        Whether the calling blob service requires objects to be decrypted.
    :param object key_encryption_key:
        The user-provided key-encryption-key. Must implement the following methods:
        wrap_key(key)--wraps the specified key using an algorithm of the user's choice.
        get_key_wrap_algorithm()--returns the algorithm used to wrap the specified symmetric key.
        get_kid()--returns a string key id for this key-encryption-key.
    :param object key_resolver:
        The user-provided key resolver. Uses the kid string to return a key-encryption-key
        implementing the interface defined above.
    :param bytes content:
        The encrypted blob content.
    :param int start_offset:
        The adjusted offset from the beginning of the *decrypted* content for the caller's data.
    :param int end_offset:
        The adjusted offset from the end of the *decrypted* content for the caller's data.
    :param Dict[str, Any] response_headers:
        A dictionary of response headers from the download request. Expected to include the
        'x-ms-meta-encryptiondata' header if the blob was encrypted.
    :return: The decrypted blob content.
    :rtype: bytes
    """
    try:
        encryption_data = _dict_to_encryption_data(loads(response_headers['x-ms-meta-encryptiondata']))
    except Exception as exc:  # pylint: disable=broad-except
        if require_encryption:
            raise ValueError(
                'Encryption required, but received data does not contain appropriate metadata.' + \
                'Data was either not encrypted or metadata has been lost.') from exc

        return content

    algorithm = encryption_data.encryption_agent.encryption_algorithm
    if algorithm not in(_EncryptionAlgorithm.AES_CBC_256, _EncryptionAlgorithm.AES_GCM_256):
        raise ValueError('Specified encryption algorithm is not supported.')

    version = encryption_data.encryption_agent.protocol
    if version not in (_ENCRYPTION_PROTOCOL_V1, _ENCRYPTION_PROTOCOL_V2):
        raise ValueError('Specified encryption version is not supported.')

    content_encryption_key = _validate_and_unwrap_cek(encryption_data, key_encryption_key, key_resolver)

    if version == _ENCRYPTION_PROTOCOL_V1:
        blob_type = response_headers['x-ms-blob-type']

        iv = None
        unpad = False
        if 'content-range' in response_headers:
            content_range = response_headers['content-range']
            # Format: 'bytes x-y/size'

            # Ignore the word 'bytes'
            content_range = content_range.split(' ')

            content_range = content_range[1].split('-')
            content_range = content_range[1].split('/')
            end_range = int(content_range[0])
            blob_size = int(content_range[1])

            if start_offset >= 16:
                iv = content[:16]
                content = content[16:]
                start_offset -= 16
            else:
                iv = encryption_data.content_encryption_IV

            if end_range == blob_size - 1:
                unpad = True
        else:
            unpad = True
            iv = encryption_data.content_encryption_IV

        if blob_type == 'PageBlob':
            unpad = False

        cipher = _generate_AES_CBC_cipher(content_encryption_key, iv)
        decryptor = cipher.decryptor()

        content = decryptor.update(content) + decryptor.finalize()
        if unpad:
            unpadder = PKCS7(128).unpadder()
            content = unpadder.update(content) + unpadder.finalize()

        return content[start_offset: len(content) - end_offset]

    if version == _ENCRYPTION_PROTOCOL_V2:
        # We assume the content contains only full encryption regions
        total_size = len(content)
        offset = 0

        nonce_length = encryption_data.encrypted_region_info.nonce_length
        data_length = encryption_data.encrypted_region_info.data_length
        tag_length = encryption_data.encrypted_region_info.tag_length
        region_length = nonce_length + data_length + tag_length

        decrypted_content = bytearray()
        while offset < total_size:
            # Process one encryption region at a time
            process_size = min(region_length, total_size)
            encrypted_region = content[offset:offset + process_size]

            # First bytes are the nonce
            nonce = encrypted_region[:nonce_length]
            ciphertext_with_tag = encrypted_region[nonce_length:]

            aesgcm = AESGCM(content_encryption_key)
            decrypted_data = aesgcm.decrypt(nonce, ciphertext_with_tag, None)
            decrypted_content.extend(decrypted_data)

            offset += process_size

        # Read the caller requested data from the decrypted content
        return decrypted_content[start_offset:end_offset]

    raise ValueError('Specified encryption version is not supported.')

    Decrypts the given blob contents and returns only the requested range.

    :param bool require_encryption:
        Whether the calling blob service requires objects to be decrypted.
    :param object key_encryption_key:
        The user-provided key-encryption-key. Must implement the following methods:
        wrap_key(key)--wraps the specified key using an algorithm of the user's choice.
        get_key_wrap_algorithm()--returns the algorithm used to wrap the specified symmetric key.
        get_kid()--returns a string key id for this key-encryption-key.
    :param object key_resolver:
        The user-provided key resolver. Uses the kid string to return a key-encryption-key
        implementing the interface defined above.
    :param bytes content:
        The encrypted blob content.
    :param int start_offset:
        The adjusted offset from the beginning of the *decrypted* content for the caller's data.
    :param int end_offset:
        The adjusted offset from the end of the *decrypted* content for the caller's data.
    :param Dict[str, Any] response_headers:
        A dictionary of response headers from the download request. Expected to include the
        'x-ms-meta-encryptiondata' header if the blob was encrypted.
    :return: The decrypted blob content.
    :rtype: bytes
    
Solutions/CyberArkAudit/Data Connectors/.python_packages/lib/site-packages/azure/storage/blob/_encryption.py