简体   繁体   中英

Decrypt with Fernet, TypeError: token must be bytes

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:\Users\hirusha\AppData\Local\Programs\Python\Python38\lib\site-packages\cryptography\fernet.py", line 75, in decrypt
    timestamp, data = Fernet._get_unverified_token_data(token)
  File "C:\Users\hirusha\AppData\Local\Programs\Python\Python38\lib\site-packages\cryptography\fernet.py", line 100, in _get_unverified_token_data
    utils._check_bytes("token", token)
  File "C:\Users\hirusha\AppData\Local\Programs\Python\Python38\lib\site-packages\cryptography\utils.py", line 29, in _check_bytes
    raise TypeError("{} must be bytes".format(name))
TypeError: token must be byte

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)

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'\xe7\xa8\xb2\xe5\xa6\xbb\xe3\x81\xae\xe8\x85\x95\xe3\x82\x92\xe5\x80\x9f\xe3\x82\x89\xe3\x82\x93\xe8\x8d\x89\xe6\x9e\x95'
>>> text.encode('utf-16')
b'\xff\xfe2z\xbbYn0U\x81\x920\x1fP\x890\x930I\x83\x95g'
>>> 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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM