You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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,请求解决该问题。


解决方案

  1. 解决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())
  1. 补充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)
  1. 修正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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 14:47:06