def encrypt_blob(blob, key_encryption_key, version):
    '''
    Encrypts the given blob using the given encryption protocol version.
    Wraps the generated content-encryption-key using the user-provided key-encryption-key (kek).
    Returns a json-formatted string containing the encryption metadata. This method should
    only be used when a blob is small enough for single shot upload. Encrypting larger blobs
    is done as a part of the upload_data_chunks method.

    :param bytes blob:
        The blob to be encrypted.
    :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 str version: The client encryption version to use.
    :return: A tuple of json-formatted string containing the encryption metadata and the encrypted blob data.
    :rtype: (str, bytes)
    '''

    _validate_not_none('blob', blob)
    _validate_not_none('key_encryption_key', key_encryption_key)
    _validate_key_encryption_key_wrap(key_encryption_key)

    if version == _ENCRYPTION_PROTOCOL_V1:
        # AES256 uses 256 bit (32 byte) keys and always with 16 byte blocks
        content_encryption_key = os.urandom(32)
        initialization_vector = os.urandom(16)

        cipher = _generate_AES_CBC_cipher(content_encryption_key, initialization_vector)

        # PKCS7 with 16 byte blocks ensures compatibility with AES.
        padder = PKCS7(128).padder()
        padded_data = padder.update(blob) + padder.finalize()

        # Encrypt the data.
        encryptor = cipher.encryptor()
        encrypted_data = encryptor.update(padded_data) + encryptor.finalize()

    elif version == _ENCRYPTION_PROTOCOL_V2:
        # AES256 GCM uses 256 bit (32 byte) keys and a 12 byte nonce.
        content_encryption_key = os.urandom(32)
        initialization_vector = None

        data = BytesIO(blob)
        encryption_stream = GCMBlobEncryptionStream(content_encryption_key, data)

        encrypted_data = encryption_stream.read()

    else:
        raise ValueError("Invalid encryption version specified.")

    encryption_data = _generate_encryption_data_dict(key_encryption_key, content_encryption_key,
                                                     initialization_vector, version)
    encryption_data['EncryptionMode'] = 'FullBlob'

    return dumps(encryption_data), encrypted_data

    Encrypts the given blob using the given encryption protocol version.
    Wraps the generated content-encryption-key using the user-provided key-encryption-key (kek).
    Returns a json-formatted string containing the encryption metadata. This method should
    only be used when a blob is small enough for single shot upload. Encrypting larger blobs
    is done as a part of the upload_data_chunks method.

    :param bytes blob:
        The blob to be encrypted.
    :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 str version: The client encryption version to use.
    :return: A tuple of json-formatted string containing the encryption metadata and the encrypted blob data.
    :rtype: (str, bytes)
    
Solutions/CyberArkAudit/Data Connectors/.python_packages/lib/site-packages/azure/storage/blob/_encryption.py