本教程详细介绍了如何使用 python 的 cryptography 库中的 fernet 模块实现文件的加密与解密操作。文章将涵盖 fernet 密钥的生成、管理与重用,以及如何在文件中安全地执行加密和解密过程,并强调密钥安全存储的重要性,确保数据机密性。
在信息安全日益重要的今天,对敏感数据进行加密是保护其机密性的基本手段。Python 的 cryptography 库提供了一套强大且易于使用的加密工具,其中 fernet 模块是实现对称加密的理想选择。Fernet 是一种基于 AES 算法的对称加密方案,它确保了消息的认证性、完整性和机密性,并且易于集成到应用程序中。
Fernet 的核心原理在于使用一个共享的密钥进行数据的加密和解密。这意味着,加密数据所使用的密钥必须与解密数据所使用的密钥完全一致。如果密钥丢失或泄露,数据将无法恢复或面临被未授权访问的风险。
在使用 Fernet 进行文件加密和解密之前,我们需要理解其两个关键概念:密钥生成和 Fernet 实例的创建。
Fernet 密钥是一个32字节的 URL 安全的 Base64 编码字符串。它是对称加密的基础,必须严格保密。通过 Fernet.generate_key() 方法可以生成一个全新的密钥。
from cryptography.fernet import Fernet
# 生成一个 Fernet 密钥
key = Fernet.generate_key()
print(f"生成的 Fernet 密钥 (Base64编码): {key
.decode()}")重要提示: 每次调用 Fernet.generate_key() 都会生成一个全新且不同的密钥。对于需要持久化加密的数据,您必须将生成的密钥保存下来并在后续的解密操作中重用它。
拥有密钥后,您可以使用它来创建一个 Fernet 实例。这个实例将用于执行实际的加密和解密操作。
# 使用生成的密钥创建 Fernet 实例 cipher = Fernet(key)
Fernet 实例提供了 encrypt() 和 decrypt() 方法来处理字节数据。对于文件操作,我们通常需要以二进制模式读取文件内容,进行加密或解密,然后再将处理后的内容写入文件。
以下代码示例展示了如何在一个函数中实现文件的原地(in-place)加密和解密。这意味着文件内容会被直接替换为加密或解密后的数据。
import os
from cryptography.fernet import Fernet
from cryptography.fernet import InvalidToken # 用于处理解密失败异常
def process_file_in_place(filename: str, cipher: Fernet, action: str, debug: bool = False):
"""
对文件内容进行原地加密或解密。
Args:
filename (str): 要处理的文件路径。
cipher (Fernet): Fernet 加密实例。
action (str): 操作类型,可以是 "encrypt" 或 "decrypt"。
debug (bool): 是否在加密后打印加密内容。
"""
# 以二进制读写模式打开文件 (rb+ 允许读写,文件指针初始在开头)
with open(filename, "rb+") as data_file:
content = data_file.read() # 读取文件所有内容
# 根据指定操作执行加密或解密
processed_content = b""
if action == "encrypt":
processed_content = cipher.encrypt(content)
if debug:
print(f"加密后的内容 (bytes): {processed_content}")
elif action == "decrypt":
try:
processed_content = cipher.decrypt(content)
if debug:
print(f"解密后的内容 (bytes): {processed_content}")
except InvalidToken:
print(f"错误: 无法解密文件 '{filename}'。可能是密钥不匹配或数据已损坏。")
return # 解密失败,退出函数
else:
raise ValueError("操作类型必须是 'encrypt' 或 'decrypt'")
# 将文件指针移到文件开头
data_file.seek(0)
# 写入处理后的内容
data_file.write(processed_content)
# 如果新内容比旧内容短,则截断文件,确保文件大小正确
data_file.truncate()
if __name__ == "__main__":
test_filename = "example_data.txt"
original_text = "Hello, world! This is a secret message that needs to be protected."
# 1. 创建一个原始的明文文件
with open(test_filename, "w", encoding="utf-8") as f:
f.write(original_text)
print(f"原始文件 '{test_filename}' 内容: {original_text}")
# 2. 生成一个 Fernet 密钥并创建实例
# 注意:此密钥仅用于本次运行,实际应用中需要持久化存储
key_for_example = Fernet.generate_key()
cipher_for_example = Fernet(key_for_example)
print(f"生成的 Fernet 密钥 (Base64编码): {key_for_example.decode()}")
# 3. 加密文件
print("\n--- 执行加密 ---")
process_file_in_place(test_filename, cipher_for_example, "encrypt", debug=True)
with open(test_filename, "rb") as f:
print(f"加密后文件 '{test_filename}' 的二进制内容 (部分): {f.read()[:50]}...") # 只打印前50字节
# 4. 解密文件
print("\n--- 执行解密 ---")
process_file_in_place(test_filename, cipher_for_example, "decrypt")
with open(test_filename, "r", encoding="utf-8") as f: # 解密后内容可按文本读取
decrypted_text = f.read()
print(f"解密后文件 '{test_filename}' 内容: {decrypted_text}")
# 5. 验证解密内容是否与原始内容匹配
assert decrypted_text == original_text
print("\n验证成功:解密内容与原始内容一致。")
# 清理测试文件
if os.path.exists(test_filename):
os.remove(test_filename)代码解析:
在实际应用中,每次运行程序都生成新密钥是不可行的。为了能够在不同时间点或不同程序实例之间加密和解密数据,密钥必须被持久化存储并重用。
正确的密钥持久化
# python
# 编码
# 字节
# 工具
# ai
# 敏感数据
# 持久化存储
# crypto
# elif
相关栏目:
【
Google疑问12 】
【
Facebook疑问10 】
【
网络优化76771 】
【
技术知识130152 】
【
IDC云计算60162 】
【
营销推广131313 】
【
AI优化88182 】
【
百度推广37138 】
【
网站推荐60173 】
【
精选阅读31334 】
相关推荐:
Win10系统怎么查看网络连接状态_Windows10网络和共享中心
Win11触摸板没反应怎么办_开启Win11笔记本触摸板手势教程【步骤】
c++20的std::format怎么用 比printf更安全高效的格式化方法【详解】
如何在Golang中使用replace替换模块_指定本地或远程路径
c++ std::future和std::promise c++线程间通信【教程】
如何在Golang中实现微服务服务拆分_Golang微服务拆分与接口管理方法
Win11时间格式怎么改成12小时制 Win11时间格式切换教程【步骤】
Mac的“预览”如何合并多个PDF_Mac文件处理技巧【效率】
Win11怎么开启窗口对齐助手_Windows11系统多任务处理设置
Windows蓝屏BAD_POOL_HEADER故障详解_蓝屏池损坏错误修复指南
Win11怎么开启移动热点_Windows11共享网络给手机设置教程
php下载安装包怎么选_threadsafe与nts版本差异【解答】
c++怎么实现高并发下的无锁队列_c++ std::atomic原子变量与CAS操作【详解】
C#如何使用XPathNavigator高效查询XML
Mac如何整理桌面文件_Mac使用堆栈功能一键整理
php485支持哪些操作系统_php485跨系统支持情况介绍【解答】
如何使用Golang构建简易投票统计功能_Golang投票数据汇总与展示示例
Win11任务栏颜色怎么改_Win11自定义任务栏配色设置【美化】
PhpStorm怎么调试PHP代码_PhpStorm断点设置与调试启动步骤【指南】
MAC怎么设置程序窗口永远最前_MAC窗口置顶插件安装与快捷设置【方法】
Win11怎样安装剪映专业版_Win11安装剪映教程【步骤】
如何在Golang中编写异步函数测试_Golang异步操作测试策略
php命令行怎么运行_通过CLI模式执行PHP脚本的步骤【说明】
Win11怎么设置环境变量_Win11配置Path路径变量【详解】
XML的“混合内容”是什么 怎么用DTD或XSD定义
Go 中 defer 在 goroutine 内部不生效的原因与执行时机详解
Win11任务栏天气怎么关闭 Win11隐藏天气小组件图标【设置】
Go 中 := 短变量声明的类型推导机制详解
c# Task.ConfigureAwait(true) 在什么场景下是必须的
MAC如何快速搜索大文件_MAC磁盘空间分析与冗余数据清理【方法】
Windows的便笺功能如何使用?(桌面备忘技巧)
c++如何用AFL++进行模糊测试 c++ Fuzzing入门【安全】
如何使用Golang实现跨域请求支持_Golang CORS配置与处理方法
Windows如何使用注册表查找和删除项?(regedit教程)
php中::能访问全局变量吗_全局作用域与类作用域区分【操作】
c++中explicit(bool)的用法 c++条件性explicit【C++20】
PyTorch DDP 多进程训练在 Kaggle 笔记本中的正确启动方式
Win11怎样安装网易云音乐_Win11安装网易云教程【步骤】
Win11怎么清理C盘虚拟内存_Win11清理虚拟内存设置【教程】
Win11怎么清理C盘下载文件夹_Win11清理下载文件夹技巧【教程】
Windows10无法连接到Internet_Win10网络重置命令详解
Win11怎么关闭定位服务 Win11禁止应用获取位置信息【隐私】
Win11怎么关闭定位服务_保护Win11位置隐私设置指南【详解】
如何使用Golang log设置日志输出格式_Golang log日志格式示例
Win11蓝牙开关不见了怎么办_Win11蓝牙驱动丢失修复教程【方法】
Windows11怎么用“记事本”自动换行与编码 Windows11记事本启用自动换行选择UTF-8编码避免乱码兼容多语言【教程】
Win11怎么关闭自动调节屏幕亮度_Windows11禁用内容自适应亮度控制
Win11怎么设置默认邮件应用_Windows11应用关联Mail设置
Win11如何更改任务栏颜色 Win11自定义任务栏背景色【美化】
Win11开机速度慢怎么优化_Win11系统启动加速设置指南【方法】
2025-11-10
致胜网络推广营销网专注海外推广十年,是谷歌推广.Facebook广告全球合作伙伴,我们精英化的技术团队为企业提供谷歌海外推广+外贸网站建设+网站维护运营+Google SEO优化+社交营销为您提供一站式海外营销服务。