使用Python Fernet模块解密文件时遇AttributeError问题求助
使用Fernet模块实现文件加解密时遇到AttributeError问题
我正在用Python的Fernet模块实现文件加解密功能,相关代码如下:
def encrypt(self): if not os.path.exists(self.filename): raise Exception('File does not exist!') # Generate a random salt salt = Fernet.generate_key() # Calculate the HMAC of the salt using the key hmac_digest = hmac.new(self.key, salt, hashlib.sha256).digest() # Encrypt the data with the salt and key fernet = Fernet(salt + self.key) with open(self.filename, 'rb') as file: file_data = file.read() encrypted_data = fernet.encrypt(file_data) # Write the encrypted data to the file with open(self.filename, 'wb') as file: file.write(encrypted_data) def decrypt(self): if not os.path.exists(self.filename): raise Exception('File does not exist!') # Read the salt and HMAC digest from the separate file with open(self.filename + '.salt', 'rb') as file: k_sz = Fernet.key_size salt = file.read(k_sz) hmac_digest = file.read(hashlib.sha256().digest_size)
在decrypt方法中尝试从对应.salt文件读取salt和HMAC摘要时,出现如下错误:
File "C:\python programs\test2.py", line 61, in decrypt k_sz = Fernet.key_size ^^^^^^^^^^^^^^^ AttributeError: type object 'Fernet' has no attribute 'key_size'
我试过用.KEY_SIZE以及Fernet(key=None).key_size,前者提示无此属性,后者提示key不能为None,请求解决该问题。
解决方案
- 解决
key_size不存在的问题
Fernet类本身没有key_size或KEY_SIZE属性,你需要通过len(Fernet.generate_key())来获取加密时生成的salt长度——因为你在encrypt方法中用Fernet.generate_key()生成salt,这个方法返回固定长度的bytes(44字节,base64url编码后的32字节原始密钥)。修改decrypt方法中的代码:
k_sz = len(Fernet.generate_key())
- 补充encrypt方法的缺失逻辑
你的encrypt方法没有将生成的salt和hmac_digest写入到.salt文件中,会导致decrypt时读取不到有效数据。在encrypt方法末尾添加以下代码:
# 写入salt和HMAC摘要到.salt文件 with open(self.filename + '.salt', 'wb') as salt_file: salt_file.write(salt) salt_file.write(hmac_digest)
- 修正Fernet密钥初始化的错误
当前Fernet(salt + self.key)的写法不符合Fernet的密钥要求——Fernet要求密钥必须是base64url编码的32字节原始数据,直接拼接salt和key生成的字符串会导致加密/解密失败。正确的做法是用salt派生符合要求的Fernet密钥,示例如下:
import base64 from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC from cryptography.hazmat.backends import default_backend def encrypt(self): if not os.path.exists(self.filename): raise Exception('File does not exist!') # 生成16字节的随机salt(推荐长度) salt = os.urandom(16) # 通过PBKDF2HMAC派生符合Fernet要求的密钥 kdf = PBKDF2HMAC( algorithm=hashlib.sha256(), length=32, salt=salt, iterations=100000, backend=default_backend() ) # 派生后进行base64url编码,得到Fernet可用的密钥 fernet_key = base64.urlsafe_b64encode(kdf.derive(self.key)) fernet = Fernet(fernet_key) # 计算salt的HMAC摘要 hmac_digest = hmac.new(self.key, salt, hashlib.sha256).digest() # 加密文件数据 with open(self.filename, 'rb') as file: file_data = file.read() encrypted_data = fernet.encrypt(file_data) # 写入加密后的数据到原文件 with open(self.filename, 'wb') as file: file.write(encrypted_data) # 写入salt和HMAC摘要到.salt文件 with open(self.filename + '.salt', 'wb') as salt_file: salt_file.write(salt) salt_file.write(hmac_digest)
对应的decrypt方法中,salt长度改为16即可,或者在写入.salt文件时先写入salt长度,再写入salt和hmac_digest,这样更灵活。
内容的提问来源于stack exchange,提问作者Adarsh Kumar
相关产品推荐
相关产品推荐

