Ошибка Signature did not match digest и cryptography.fernet.InvalidToken при шифровании пароля

Делаю проект менеджера паролей с шифрованием паролей. Остановился на окне с вводом мастер-пароля. Ошибка заключается в том, что при перезапуске кода Fernet пишет о том, что подпись не соответствует чему-то, а также что сам ключ недействителен. Однако я почти полностью уверен что ключ никак не изменяется и хранится в файле key.key. Обновляется ключ только вручную, если использовать "восстановление пароля", причем после этой операции ключ подтверждается и приложение открывает следующий файл с основным кодом приложения.

from tkinter import *
from tkinter import messagebox
import os
from cryptography.fernet import Fernet


root = Tk()
root.title('Авторизация')
root.geometry('925x500+300+200')
root.config(bg="#fff")
root.resizable(False, False)
Flag = False


# ---------Sign in Function-----------


def signin():
    global Flag, code
    password = code.get()

    with open('stcn.txt', 'r') as f:
        data = f.readline().rstrip()
        f.close()
        anc = fer.decrypt(data.encode()).decode()
        print(anc)
        if anc == password:
            Flag = True
            root.destroy()
        else:
            messagebox.showerror("Ошибка", "Введите верный пароль \n"
                                    "При первом входе в систему воспользуйтесь восстановлением пароля")


# ---------Image Here----------


img = PhotoImage(file='images/login.png')
Label(root, image=img, bg='white').place(x=50, y=50)

# ------------Frame-------------

frame = Frame(root, width=350, height=350, bg='white')
frame.place(x=480, y=70)

heading = Label(frame, text='Авторизация', fg='#57a1f8', bg='white',
                font=('Microsoft YaHei UI Light', 23, 'bold'))
heading.place(x=100, y=5)

info = Label(frame, text="Введите текущий мастер-пароль", fg="Black", bg="white")
info.place(x=25, y=180)


# ------------Password Functions------------


def on_enter(e):
    code.delete(0, 'end')


def on_leave(e):
    cname = code.get()
    if cname == '':
        code.insert(0, 'Пароль')


def delall():
    res = messagebox.askokcancel(title="Удалить все сохранённые пароли?",
                                 message="Если вы забыли мастер-пароль, или хотите создать новый, то приложение не сможет расшифровать сохранённые пароли. \n \n"
                                         "В этом случае можно только удалить все сохраненные в базе данных пароли и создать новый мастер-пароль. \n \n"
                                         "НАЖМИТЕ 'ОК', ЕСЛИ ХОТИТЕ УДАЛИТЬ ВСЕ ПАРОЛИ")
    if res:
        os.remove("PasswordEncrMngr.db")
        r = open("PasswordEncrMngr.db", "w+")
        r.close()
        messagebox.showinfo("Учетные данные удалены", "Все учетные данные удалены")
        pwdwnd = Tk()
        pwdwnd.title("Создание нового мастер-пароля")
        pwdwnd.config(bg='white', border=0)
        pwdwnd.geometry("400x150")
        pwdwnd.wm_attributes('-alpha')

        # def onpwdentry(evt):
        #     write_key()
        #     scnt = pwdbox.get()
        #     with open('stcn.txt', 'a') as f:
        #         f.write(fer.encrypt(scnt.encode()).decode() + "\n")
        #         f.close()
        #     pwdwnd.destroy()

        def onokclick():
            write_key()
            scnt = pwdbox.get()
            with open('stcn.txt', 'w') as f:
                f.write(fer.encrypt(scnt.encode()).decode())
                f.close()
            pwdwnd.destroy()

        Label(pwdwnd, text='Введите новый мастер-пароль', font=('Microsoft YaHei UI Light', 16, 'bold'),
              bg='white').place(x=40, y=20)
        pwdbox = Entry(pwdwnd, show='*', fg="black", border=0, bg="white", width=30,
                       font=('Microsoft YaHei UI Light', 11))
        pwdbox.place(x=80, y=70)
        Frame(pwdwnd, width=250, height=2, bg='black').place(x=75, y=95)
        Button(pwdwnd, command=onokclick, text='Сохранить новый пароль', border=0, background='#57a1f8', width=22,
               height=1).place(x=130, y=110)
    else:
        pass


def write_key():
    global key
    key = Fernet.generate_key()
    with open("key.key", "wb") as key_file:
        key_file.write(key)


def load_key():
    global key
    file = open("key.key", 'rb')
    key = file.read()
    file.close()
    return key


# write_key()
key = load_key()
fer = Fernet(key)
print(key)

# -----------------------------------
code = Entry(frame, width=30, fg='black', show="•", border=0,
             bg='white', font=('Microsoft YaHei UI Light', 11))
code.place(x=30, y=150)
code.bind('<FocusIn>', on_enter)
code.bind('<FocusOut>', on_leave)

Frame(frame, width=295, height=2, bg='black').place(x=25, y=177)

# ----------------------------------
Button(frame, width=39, pady=7, text='Продолжить',
       bg='#57a1f8', fg='white', border=0, command=signin).place(x=35, y=204)

sign_up = Button(frame, width=39, text='Не помню пароль или создать новый', border=0,
                 bg='white', cursor='hand2', fg='#57a1f8', command=delall)
sign_up.place(x=40, y=250)

root.mainloop()

Вот такая ошибка выходит при выполнении кода:

Exception in Tkinter callback
Traceback (most recent call last):
  File "EncryptManager\.venv\Lib\site-packages\cryptography\fernet.py", line 130, in _verify_signature
    h.verify(data[-32:])
cryptography.exceptions.InvalidSignature: Signature did not match digest.

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "C:\Users\AppData\Local\Programs\Python\Python312\Lib\tkinter\__init__.py", line 1967, in __call__
    return self.func(*args)
           ^^^^^^^^^^^^^^^^
  File "C:\Users\Файлы\ДГТУ\Учебная ознакомительная практика\Проект\EncryptManager\welcome.py", line 25, in signin
    anc = fer.decrypt(data.encode()).decode()
          ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "EncryptManager\.venv\Lib\site-packages\cryptography\fernet.py", line 89, in decrypt
    return self._decrypt_data(data, timestamp, time_info)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "EncryptManager\.venv\Lib\site-packages\cryptography\fernet.py", line 148, in _decrypt_data
    self._verify_signature(data)
  File "EncryptManager\.venv\Lib\site-packages\cryptography\fernet.py", line 132, in _verify_signature
    raise InvalidToken
cryptography.fernet.InvalidToken

Пробовал менять способы чтения и записи файлов при сохранении ключа и исходного пароля, изменяя атрибуты open() Проверял логику кода на шифрование/дешифрование, но что-то не выходит...


Ответы (1 шт):

Автор решения: Artem Savin

Такая же проблема! Все храню в бинарном виде в БД постгрес, ключ один, его уже текстом вписал вместо переменной. Если зашифровать и сразу отправить на дешифровку переменную, все хорошо работает, но если это делать разными командами то ерор!

from cryptography.fernet import Fernet
from config.data import CRIPTO_KEY

fernet = Fernet(b'xX8FN0tVdzXzgexIGQ9d51XMEIqnUiZQ2YSIohjCbFk=')


async def encrypt(data: str) -> bytes:
    encrypted = fernet.encrypt(data.encode())
    return encrypted


async def decrypt(encrypted_data: bytes) -> str:
    print('encrypted_data = ', encrypted_data)
    decrypted = fernet.decrypt(encrypted_data).decode()
    return decrypted


вывод:


encrypted_data =  b'gAAAAABmoB8uIq6bxP_NBAE5UIJBRkWHKPB4ddQepKN9vUNW5LaRQPW3YMJoc5QeeVsx5H48afLRjWPGDC3cXcr-VPRqm_S5sg=='

ошибка:


... lib/python3.10/site-packages/cryptography/fernet.py", line 118, in _get_unverified_token_data
    raise InvalidToken
cryptography.fernet.InvalidToken

→ Ссылка