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
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)
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
I used:
encMessage = input("Input encrypted message: ")
encMessage = bytes(encMessage,'utf-8')
This fixed it for me.
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
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'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
I used:
encMessage = input("Input encrypted message: ")
encMessage = bytes(encMessage,'utf-8')
This fixed it for me.