使用Fernet解密字符串

-2 投票
2 回答
75 浏览
提问于 2025-04-14 15:40

我正在做一个项目,涉及使用Fernet库来加密密码。我已经能够输入、加密并存储密码,但当我尝试取回并解密密码时,总是出现以下错误。

错误追踪(最近的调用在最前面):

File "D:\Documents\python\practiceProjects\05 passwordManager\passwordManageV2.py", line 104, in modules  
pm.view()  

File "D:\Documents\python\practiceProjects\05 passwordManager\passwordManageV2.py", line 82, in view  
print (f'\nUser:  {user},  Password:   {***Fernet(self.key).decrypt(passw)***.decode()}\n')  
 
File "C:\Users\user\AppData\Local\Programs\Python\Python312\Lib\site-packages\cryptography\fernet.py", line 84, in decrypt  

timestamp, data = ***Fernet._get_unverified_token_data(token)***

File "C:\Users\user\AppData\Local\Programs\Python\Python312\Lib\site-packages\cryptography\fernet.py", line 118, in _get_unverified_token_data  

raise InvalidToken  

cryptography.fernet.InvalidToken<br/>

用来取回和解密密码的代码是:

from cryptography.fernet import Fernet
import glob
import os

class PasswordManager:
    def __init__(self):
        self.key = None
        self.password_file = None
                
    def load_key (self):
        with open('key.key', 'rb') as f:
                self.key = f.read()
        
    def num_file_check (self):
        file = glob.glob('*.txt')
        
        self.password_file = file[0]
        
        if self.key == None:
            self.load_key ()


    def view (self):
        
        self.num_file_check ()
        
        with open(self.password_file, 'r') as f:
            for line in f.readlines():
                data = line 
                try:
                    user, passw = data.split(":")
                    print (f'\nUser:  {user},  Password:   {Fernet(self.key).decrypt(passw).decode()}\n')
                except ValueError:
                    continue

pm = PasswordManager ()
pm.view()

我尝试按照建议在with open(self.password_file, 'r') as f:中添加'rb',但是我收到了:

类型错误:需要一个字节对象,而不是'str',在user, passw = data.split(":").*

self.key的形式是b'key',而只有去掉b' '的密钥被存储在key.key文件中。此外,当我查看密码文件时,可以看到密码在写入文件之前已经被加密了。

Site:b'gAAAAABl9KjKHh4MaltYyguafWmjwNjd35wbvfyMZMZEu-t3pabud_B7TDRIjVBaAWKkeZURYN0IGDsKD2XKkdtN2yycFrBlrw=='

2 个回答

0

我在想,你是不是没有以二进制模式来读写你的文件?这里有一个可以正常工作的例子。

用来写入密钥和加密数据的代码:

from cryptography.fernet import Fernet

data = "my deep dark secret"

key = Fernet.generate_key()
f = Fernet(key)
token = f.encrypt(data.encode())

with open("example.key", "wb") as fd:
    fd.write(key)

with open("example.data", "wb") as fd:
    fd.write(token)

用来读取密钥和解密数据的代码:

from cryptography.fernet import Fernet

with open("example.key", "rb") as fd:
    key = fd.read()

f = Fernet(key)

with open("example.data", "rb") as fd:
    token = fd.read()

data = f.decrypt(token)
print(data.decode())

注意,这段代码会把原始字符串转换成utf-8格式,然后在我们解密数据时再把它转换回Python字符串。

0

没有提供输入文件,不过如果密码文件里有一个叫 Site 的条目,就说明输入文件写错了,里面不应该有 b'' 这样的内容,因为这是 bytes 对象的 str() 表示方式。

下面的代码会生成一个新的 key.key 文件和一个 passwords.txt 文件,分别包含加密密钥和几行用户名/密码。原作者的代码经过修改,可以正确读取这些文件:

from cryptography.fernet import Fernet

def generate_test_files():
    key = Fernet.generate_key()  # result is bytes object
    with open('key.key', 'wb') as file:  # so write in binary
        file.write(key)
    f = Fernet(key)

    # Write as UTF-8 to support all Unicode characters for user name.
    with open('passwords.txt', 'w', encoding='utf8') as file:
        for user, password in (('Marco', 'contraseña'), ('马克', '密码')):
            # Encrypt the UTF-8-encoded password.
            # Decode the bytes object as ASCII, which is a subset of UTF-8.
            # UTF-8 would work too, since the encryption is only ASCII bytes.
            # The resulting Unicode object can be written to the file.
            password = f.encrypt(password.encode()).decode('ascii')
            print(f'{user}:{password}', file=file)

class PasswordManager:
    def __init__(self):
        self.load_key()
        self.password_file = 'passwords.txt'

    def load_key(self):
        with open('key.key', 'rb') as f:
                self.key = f.read()

    def view(self):
        with open(self.password_file, encoding='utf8') as f:
            for line in f:
                user, passw = line.split(':')  # no b'' now to mess it up
                # Encode str password to bytes and decrypt.
                # Decode to print without b''.
                print(f'User:     {user}\nPassword: {Fernet(self.key).decrypt(passw.encode()).decode()}\n')

generate_test_files()
pm = PasswordManager()
pm.view()

输出结果:

key.key(仅包含ASCII字符):

3DZpe5WlOPFj_EQnSAXTUbOGbQvf-JKV6lILx5JIvAo=

passwords.txt(UTF-8编码):

Marco:gAAAAABl9PuidgvythraNfo5_JhnbIltp4g54Ej5TVPXj5Ec0PVCZellsASafgnOcdCY4In77yjaBroKgDXiRWtSygSYzTuiPw==
马克:gAAAAABl9PujHyIYpvmzeo909kt6LFT6_I1ya098vFsoRCukX48WjoqWUniVOcB0jqZ5aOr1VAXYIr_p7Q80XCYBFo3RhEUVSA==

终端(取决于字体支持):

User:     Marco
Password: contraseña

User:     马克
Password: 密码

撰写回答