def encrypt(byte_data, secret_key=''):

    '''
        uses cryptography module to encrypt byte data
        cipher: AES (128 bit block_size)
        hash: sha512
        key size: 256 bit (first 32 bytes of secret key hash)
        vector size: 128 bit (next 16 bytes of secret key hash)
        padding: PKCS7
        cipher mode: CBC
        backend: openssl 1.0.2a

        NOTE:   if secret_key is left blank,
                method generates a 32 byte hexadecimal string

    :param byte_data: bytes with data to encrypt
    :param secret_key: [optional] string used to encrypt data
    :return: encrypted byte data, secret key hex string
    '''

# validate input
    if not isinstance(byte_data, bytes):
        raise TypeError('\nbyte data input must be a byte datatype.')

# validate secret key or create secret key
    if secret_key:
        if not isinstance(secret_key, str):
            raise TypeError('\nsecret key input must be a utf-8 encoded string.')
    else:
        from os import urandom
        from binascii import hexlify
        secret_key = hexlify(urandom(32)).decode()

# retrieve cipher key and initialization vector from sha256 hash of secret key
    key_bytes = hashlib.sha512(secret_key.encode('utf-8')).digest()
    cipher_key = key_bytes[0:32]
    cipher_vector = key_bytes[32:48]

# construct encryptor
    cipher_kwargs = {
        'algorithm': algorithms.AES(cipher_key),
        'mode': modes.CBC(cipher_vector),
        'backend': openssl.backend
    }
    cipher = Cipher(**cipher_kwargs)
    encryptor = cipher.encryptor()

# encrypt and add padding
    padder = padding.PKCS7(128).padder()
    padded_data = padder.update(byte_data)
    padded_data += padder.finalize()
    encrypted_data = encryptor.update(padded_data) + encryptor.finalize()

    return encrypted_data, secret_key