Python 密码管理器的Fernet无效令牌错误

Python 密码管理器的Fernet无效令牌错误,python,python-3.x,file,encryption,cryptography,Python,Python 3.x,File,Encryption,Cryptography,我目前正在尝试使用加密模块在Python中创建一个自定义的小密码管理器。使用主密码进行加密似乎没有问题,但解密会导致2个错误: 代码如下: import os import base64 import pickle from cryptography.fernet import Fernet from cryptography.hazmat.backends import default_backend from cryptography.hazmat.primitives import ha

我目前正在尝试使用加密模块在Python中创建一个自定义的小密码管理器。使用主密码进行加密似乎没有问题,但解密会导致2个错误:

代码如下:

import os
import base64
import pickle
from cryptography.fernet import Fernet
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC

logins = {}
masterpass = bytes(input('Unlock login ring with master password: '), 'utf-8')

def newLogin(email, username, password):
    logins['{}:{}'.format(email, username)] = password

def loadLogins():
    salt = os.urandom(16)
    kdf = PBKDF2HMAC(
        algorithm=hashes.SHA256(),
        length=32,
        salt=salt,
        iterations=100000,
        backend=default_backend()
    )

    key = base64.urlsafe_b64encode(kdf.derive(masterpass))

    f = Fernet(key)

    file = open('keyring.keys', 'rb')

    token = f.decrypt(file.read())

    print(file.read())

    file.close()
    

def saveLogins():
    salt = os.urandom(16)
    kdf = PBKDF2HMAC(
        algorithm=hashes.SHA256(),
        length=32,
        salt=salt,
        iterations=100000,
        backend=default_backend()
    )

    key = base64.urlsafe_b64encode(kdf.derive(masterpass))

    f = Fernet(key)

    logs = ['{}'.format(x) for x in logins]
    pasw = ['{}'.format(logins[y]) for y in logins]

    keys = []

    for i in range(len(logins)):
        keys += logs[i] + ':' + pasw[i] + ';'

    print(''.join(keys))

    keyring = f.encrypt(bytes(''.join(keys), 'utf-8'))

    file = open('keyring.keys', 'wb')

    pickle.dump(keyring, file)

    file.close()

我的代码的工作方式是,您必须首先给它一个主密码。然后,它将主密码存储为字节对象。接下来,您可以将登录添加/更新到登录字典。然后,使用Fernet密码配方(),我将主密码转换为Fernet密钥,用于加密和解密文件的登录。如上所述,加密工作正常,但解密总是导致错误。我的解密功能有问题吗?或者我如何实现密码加密/解密


谢谢。

对不起,我犯了愚蠢的错误。解决方案是生成一个os.uradom salt,并将其用作派生密钥的文字(也称为“幻数”)。而且,我只需要推导一次键,而不是在每个函数中

我还需要对要写入的文件调用pickle.load。以下是一个可行的解决方案:

import base64
import pickle
from cryptography.fernet import Fernet
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC

logins = {}
masterpass = bytes(input('Unlock login ring with master password: '), 'utf-8')

# Derive key from master password
kdf = PBKDF2HMAC(
    algorithm=hashes.SHA256(),
    length=32,
    salt=b'\xaab\xc0\xe0+\xc8\xb29\xc5\xe9\xbb\xfb\xaa\xb6\xab\xa7',
    iterations=100000,
    backend=default_backend()
)

key = base64.urlsafe_b64encode(kdf.derive(masterpass))

f = Fernet(key)


# Add or update login information in
# the logins dictionary.
def setLogin(website, email, username, password):
    logins[website] = '{}:{}:{}'.format(email, username, password)


# Load and decrypt the logins and
# return them in string format.
def loadLogins():
    file = open('keyring.keys', 'rb')

    token = f.decrypt( pickle.load(file) )

    file.close()

    return token.decode('utf-8')


# Separate and load logins into the
# logins dictionary.
def parseLogins(strLogins):
    individual_logins = strLogins.split(';')

    for i in range(len(individual_logins)):
        if (individual_logins[i] != ''):
            website, email, username, password = individual_logins[i].split(':')

            setLogin(website, email, username, password)
    
    print(individual_logins)


# Encrypt and save logins in a bytes file 
# using the master password.
def saveLogins():
    logs = ['{}'.format(x) for x in logins]
    pasw = ['{}'.format(logins[y]) for y in logins]

    keys = []

    for i in range(len(logins)):
        keys += logs[i] + ':' + pasw[i] + ';'

    print(''.join(keys))

    keyring = f.encrypt(bytes(''.join(keys), 'utf-8'))

    file = open('keyring.keys', 'wb')

    pickle.dump(keyring, file)

    print(keyring)

    file.close()


# Display all login information.
def showLogins():
    for i in logins:
        info = logins[i].split(':')
        
        website = i
        email = info[0]
        username = info[1]
        password = info[2]
        
        print(f'\nWebsite: {website}\nEmail: {email}\nUsername: {username}\nPassword: {password}\n')