Decrypt with Fernet, TypeError: token must be bytes

Question:

Programming language: Python

i have three files, one is to generate the key, 2nd is to encrypt, and the other is to decrypt.. the 1st and the 2nd files work.. but the decrypt file won’t work

generate key file:

from cryptography.fernet import Fernet

def generate_key():
    """
    Generates a key and save it into a file
    """
    key = Fernet.generate_key()
    with open("secret.key", "wb") as key_file:
        key_file.write(key)

generate_key()

encrypt file –

from cryptography.fernet import Fernet

def load_key():
    return open("secret.key", "rb").read()

def encrypt_message(message):
    key = load_key()
    encoded_message = message.encode()
    f = Fernet(key)
    encrypted_message = f.encrypt(encoded_message)
    
    print(encrypted_message)

    EncryptedTextWriteFile = open("encrypt.txt", "r+")
    EncryptedTextWriteFile.write(str(encrypted_message))

notEncryptedFile = open("text.txt", "r")
notEncryptedText = notEncryptedFile.read()

if __name__ == "__main__":
    encrypt_message(notEncryptedText)

notEncryptedFile.close()

Decrypt file –

from cryptography.fernet import Fernet

def load_key():
    return open("secret.key", "rb").read()

def decrypt_message(encrypted_message):
    key = load_key()
    f = Fernet(key)
    decrypted_message = f.decrypt(encrypted_message)
    shit = decrypted_message.decode()

    print(shit)

    DencryptedTextWriteFile = open("decrypt.txt", "r+")
    DencryptedTextWriteFile.write(shit)

EncryptedFile = open("decrypt.txt", "r")
EncryptedText = EncryptedFile.read()

if __name__ == "__main__":
    decrypt_message(EncryptedText)

the string i tried – ( this test is in the text.txt )

hirusha

the error i get:

Traceback (most recent call last):
  File "d:/development/Python/Everything/Releases/0.2/Build 02/_Releases/Encoder and Decoder/decrypt.py", line 27, in <module>
    decrypt_message(EncryptedText)
  File "d:/development/Python/Everything/Releases/0.2/Build 02/_Releases/Encoder and Decoder/decrypt.py", line 15, in decrypt_message
    decrypted_message = f.decrypt(encrypted_message)
  File "C:UsershirushaAppDataLocalProgramsPythonPython38libsite-packagescryptographyfernet.py", line 75, in decrypt
    timestamp, data = Fernet._get_unverified_token_data(token)
  File "C:UsershirushaAppDataLocalProgramsPythonPython38libsite-packagescryptographyfernet.py", line 100, in _get_unverified_token_data
    utils._check_bytes("token", token)
  File "C:UsershirushaAppDataLocalProgramsPythonPython38libsite-packagescryptographyutils.py", line 29, in _check_bytes
    raise TypeError("{} must be bytes".format(name))
TypeError: token must be byte
Asked By: Hirusha Adikari

||

Answers:

The problem is that when you open the file decrypt.txt and read the file, it gets converted into string. But the .decrypt function only accepts input in byte.

I think this should solve your problem:

Generates a key and stores it in key.key file:

from cryptography.fernet import Fernet
def write_key():
    """
    Generates a key and save it into a file
    """
    key = Fernet.generate_key()
    with open("key.key", "wb") as key_file:
        key_file.write(key)
write_key()

Encrypts a file and stores it in enc_text.txt file:

from cryptography.fernet import Fernet
with open("key.key","rb") as f:
    key=f.read()
f = Fernet(key)

with open('text.txt', 'rb') as original_file:
    original = original_file.read()

encrypted = f.encrypt(original)

with open ('enc_text.txt', 'wb') as encrypted_file:
    encrypted_file.write(encrypted)

Decrypts the enc_text.txt file and writes the output in decrypt.txt

from cryptography.fernet import Fernet
with open("key.key","rb") as f:
    key=f.read()
f = Fernet(key)

with open('enc_text.txt', 'rb') as encrypted_file:
    encrypted = encrypted_file.read()

decrypted = f.decrypt(encrypted)

with open('decrypt.txt', 'wb') as decrypted_file:
    decrypted_file.write(decrypted)
Answered By: user15801675

Sujay’s answer was posted while I was writing this one. It is correct, but I still wanted to post this to perhaps give some more insight into what this means.

Most (if not all) encryption tools work on bytes, not str. This is both because these days encrypting binary (non-string) data is more common, and because the encryption algorithms work on numbers, and bytes are strings of numbers in range(0, 256).

In the decryption program, you are loading the ciphertext in this line:

EncryptedFile = open("decrypt.txt", "r")

Contrast this to how you load the encryption key:

def load_key():
    return open("secret.key", "rb").read()

The difference is the mode parameter to open: if there is a b in the string, it means it operates in binary mode, working on bytes rather than str. Here’s an example:

>>> text = open('test.txt', 'r').read()
>>> text
'Hello World!n'
>>> binary = open('test.txt', 'rb').read()
>>> binary
b'Hello World!n'
>>> type(text)
<class 'str'>
>>> type(binary)
<class 'bytes'>

This distinction is important because str represents character sequences, and those can be encoded into binary in vastly different ways. Which of these you choose will affect what ones and zeros go into the encryption algorithm, and consequently what comes out.

The reason the encryption program worked, despite also reading the plaintext file in text mode, is because of this line:

encoded_message = message.encode()

str.encode converts the string into bytes using the encoding supplied, or the default one (usually UTF-8) if it is not specified. The bytes.decode method, seen in the decryption program, does the opposite: it converts bytes to str.

>>> text = '稲妻の腕を借らん草枕'
>>> text.encode()
b'xe7xa8xb2xe5xa6xbbxe3x81xaexe8x85x95xe3x82x92xe5x80x9fxe3x82x89xe3x82x93xe8x8dx89xe6x9ex95'
>>> text.encode('utf-16')
b'xffxfe2zxbbYn0Ux81x920x1fPx890x930Ix83x95g'
>>> u16_data = text.encode('utf-16')
>>> u16_data.decode('utf-16')
'稲妻の腕を借らん草枕'
>>> u16_data.decode()  # this is why specifying the encoding is important
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xff in position 0: invalid start byte
Answered By: Danya02

I used:

encMessage = input("Input encrypted message: ")
encMessage = bytes(encMessage,'utf-8')

This fixed it for me.

Answered By: user21329584
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.