0

I'm working on a tool that uses hex API keys to log a user into a remote hosted tool. For security purposes, I'm using Fernet to encrypt the keys locally and store them in a text file so the user doesn't have to enter them every time. We need to decrypt the API keys so the user can log in. The issue is that I'm loading the keys in from a text file, and I'm getting the following error when passing the string data back to Fernet:

ValueError: Fernet key must be 32 url-safe base64-encoded bytes.

Any idea what I'm doing wrong? Here are my functions:

# This function generates the local key file
def key_gen(access_key, secret_key):
    from os import getcwd
    from cryptography.fernet import Fernet
    file_data = []
    key = Fernet.generate_key()
    encrypted_ak = encrypt_data(access_key, key)
    encrypted_sk = encrypt_data(secret_key, key)
    current_dir = getcwd()
    key_file = current_dir + "\\tenableauth.txt"
    file_data.append(key)
    file_data.append(encrypted_ak)
    file_data.append(encrypted_sk)
    with open(key_file, 'w') as authentication_file:
        for line in file_data:
            authentication_file.writelines(str(line) + "\n")
    return key_file

# This function reads the local key file, and is where I'm hitting problems. Lots of test code here.
def read_keys(file):
    file_lines = []
    with open(file, 'r') as authentication_file:
        for line in authentication_file:
            file_lines.append(line)
    encryption_key = file_lines[0]
    encryption_key = encryption_key.rstrip()
    print(encryption_key)
    print(repr(encryption_key))
    decrypted_ak = decrypt_data(file_lines[1], encryption_key)
    print(decrypted_ak)

def encrypt_data(data, key):
    from cryptography.fernet import Fernet
    data = data.encode()
    encrypted_string = Fernet(key).encrypt(data)
    return encrypted_string

def decrypt_data(data, key):
    from cryptography.fernet import Fernet
    decrypted_string = Fernet(key).decrypt(data)
    return decrypted_string

1 Answers1

0

An error like that means you are mixing and matching str and bytes object types, along the way incorrectly encoding / decoding between the types

I updated the code handling between str and bytes object types as below

# This function generates the local key file
def key_gen(access_key, secret_key):
    from os import getcwd
    from cryptography.fernet import Fernet
    file_data = []
    key = Fernet.generate_key()
    encrypted_ak = encrypt_data(access_key, key)
    encrypted_sk = encrypt_data(secret_key, key)
    print(f"key {key}")
    print(f"encrypted_sk {encrypted_sk}")
    print(f"encrypted_ak {encrypted_ak}")
    key_file = "tenableauth.txt"
    file_data.append(key.decode('utf-8'))
    file_data.append(encrypted_ak.decode('utf-8'))
    file_data.append(encrypted_sk.decode('utf-8'))
    with open(key_file, 'w') as authentication_file:
        for line in file_data:
            authentication_file.write(line + '\n')
    return key_file

# This function reads the local key file, and is where I'm hitting problems. Lots of test code here.
def read_keys(file):
    file_lines = []
    with open(file, 'r') as authentication_file:
        for line in authentication_file:
            file_lines.append(line.encode('utf-8').rstrip())
    key = file_lines[0]
    encrypted_ak = file_lines[1]
    encrypted_sk = file_lines[2]
    print(f"key {key}")
    print(f"encrypted_sk {encrypted_sk}")
    print(f"encrypted_ak {encrypted_ak}")
    decrypted_ak = decrypt_data(encrypted_ak, key)
    print(decrypted_ak)

def encrypt_data(data, key):
    from cryptography.fernet import Fernet
    data = data.encode()
    encrypted_string = Fernet(key).encrypt(data)
    return encrypted_string

def decrypt_data(data, key):
    from cryptography.fernet import Fernet
    decrypted_string = Fernet(key).decrypt(data)
    return decrypted_string

With the print statement I've added, invoking key_gen("yadayada", "hoho!!") prints

key b'BtP8iJwhWqfxX6i_HwSbRASh04w3V0Ypp-M2Ic23Xlc='
encrypted_sk b'gAAAAABf67lG1a_zotxaxeG3mR6sXIgQF6jtsS6Nt8FWP7EI2f73dtBLCwWBE9fTGvEHml_ivcKxSMUjMOgOWjGSOM0uTLSDCw=='
encrypted_ak b'gAAAAABf67lGphAR1gq65o_RB2cg-o5dCLICW7o8LceKAiTEP1N4nSqlqW9pSaLumxm6CeI4bwfirSZvPDPtUtlVMeCREttvTg=='

and in reverse invokeing read_keys('tenableauth.txt') prints

key b'BtP8iJwhWqfxX6i_HwSbRASh04w3V0Ypp-M2Ic23Xlc='
encrypted_sk b'gAAAAABf67lG1a_zotxaxeG3mR6sXIgQF6jtsS6Nt8FWP7EI2f73dtBLCwWBE9fTGvEHml_ivcKxSMUjMOgOWjGSOM0uTLSDCw=='
encrypted_ak b'gAAAAABf67lGphAR1gq65o_RB2cg-o5dCLICW7o8LceKAiTEP1N4nSqlqW9pSaLumxm6CeI4bwfirSZvPDPtUtlVMeCREttvTg=='
b'yadayada'

The very last line of output is b'yadayada' the key that was passed in.

Bhaskar
  • 594
  • 2
  • 11
  • 1
    Thank you for taking the time to look at this! I had figured it was something with the relationship between bytes and strings. –  Dec 29 '20 at 23:46