Python 使用 PyPDF2 实现 PDF 加密与密码破解
前言
在数据安全日益重要的今天,保护敏感文档的访问权限是基础需求。PDF 格式因其跨平台性和安全性被广泛使用,但默认情况下 PDF 文件可能不包含强加密。本文将详细介绍如何使用 Python 的 库对 PDF 文件进行加密,以及如何通过暴力破解的方式恢复弱密码保护的 PDF 内容。这不仅有助于理解 PDF 加密机制,也能帮助开发者评估密码强度。
本文介绍了如何使用 Python 的 PyPDF2 库对 PDF 文件进行加密和解密。通过生成四位数纯数字密码进行暴力破解,实现了从加密 PDF 中恢复内容的功能。教程包含环境安装、加密函数编写、解密遍历逻辑及完整代码示例,同时强调了弱密码的安全风险和相关法律合规性。

在数据安全日益重要的今天,保护敏感文档的访问权限是基础需求。PDF 格式因其跨平台性和安全性被广泛使用,但默认情况下 PDF 文件可能不包含强加密。本文将详细介绍如何使用 Python 的 库对 PDF 文件进行加密,以及如何通过暴力破解的方式恢复弱密码保护的 PDF 内容。这不仅有助于理解 PDF 加密机制,也能帮助开发者评估密码强度。
PyPDF2首先,需要安装 PyPDF2 库。该库支持读取、写入和修改 PDF 文件。
pip install PyPDF2
安装完成后,可以通过以下命令验证版本:
python -m pip show PyPDF2
注意:PyPDF2 是一个较成熟的库,但在处理某些高级加密标准(如 AES-256)时可能存在限制。对于现代 PDF 安全需求,建议关注其后续项目 pypdf。
我们将实现两个核心功能:
PDF 加密通常基于对称加密算法(如 RC4 或 AES)。当设置密码后,文件内容会被加密,只有提供正确密钥才能解密并渲染页面。如果密码过于简单(如纯数字),攻击者可以通过穷举法(Brute Force)快速破解。
下面是一个完整的加密函数示例。该函数读取源文件,添加指定密码,并保存为新文件。
import PyPDF2
def encrypt_pdf(old_path, new_path, password='1234'):
"""
给 PDF 文件添加密码保护
:param old_path: 待加密文件的绝对路径
:param new_path: 加密后文件的保存路径
:param password: 设置的密码字符串
"""
try:
with open(old_path, 'rb') as pdf_file:
# 创建 PdfFileReader 对象
pdf_reader = PyPDF2.PdfFileReader(pdf_file)
# 创建 PdfFileWriter 对象
pdf_writer = PyPDF2.PdfFileWriter()
# 将所有页面添加到 Writer 中
for page_num in range(pdf_reader.numPages):
pdf_writer.addPage(pdf_reader.getPage(page_num))
# 设置密码并加密
pdf_writer.encrypt(user_password=password)
# 写入新文件
with open(new_path, 'wb') as result_pdf:
pdf_writer.write(result_pdf)
print(f'加密成功!文件已保存至:{new_path}')
return True
except Exception as e:
print(f'加密失败:{str(e)}')
return False
if __name__ == '__main__':
# 示例调用
# encrypt_pdf('input.pdf', 'output_encrypted.pdf', '8888')
pass
针对弱密码场景,我们可以通过遍历所有可能的字符组合来尝试解密。本例演示如何破解 4 位纯数字密码。
我们需要生成从 0000 到 9999 的所有组合。
def generate_passwords(length=4):
"""
生成指定位数的纯数字密码列表
"""
passwords = []
start = 10**(length-1) if length > 1 else 0
end = 10**length
for i in range(start, end):
passwords.append(str(i).zfill(length))
return passwords
利用 PyPDF2 提供的 decrypt() 方法验证密码有效性。
def decrypt_pdf(target_path, max_attempts=10000):
"""
尝试暴力破解 PDF 密码
:param target_path: 目标加密 PDF 路径
:param max_attempts: 最大尝试次数
""":
try:
with open(target_path, 'rb') as pdf_file:
pdf_reader = PyPDF2.PdfFileReader(pdf_file)
# 检查文件是否加密
if not pdf_reader.isEncrypted:
print('文件未加密,无需破解。')
return
print('开始尝试破解密码...')
# 遍历密码空间
for i in range(max_attempts):
pwd = str(i).zfill(4)
# 尝试解密
status = pdf_reader.decrypt(pwd)
if status > 0: # 状态大于 0 表示解密成功
print(f'破解成功!密码为:{pwd}')
# 可选:输出解密后的内容或保存副本
pdf_writer = PyPDF2.PdfFileWriter()
for pageNum in range(pdf_reader.numPages):
pdf_writer.addPage(pdf_reader.getPage(pageNum))
output_path = target_path.replace('.pdf', '_decrypted.pdf')
with open(output_path, 'wb') as out_file:
pdf_writer.write(out_file)
print(f'已保存解密文件至:{output_path}')
break
else:
# 为了减少日志噪音,可定期打印进度
if i % 1000 == 0 and i != 0:
print(f'尝试了 {i} 个密码...')
else:
print('未找到匹配的密码。')
except FileNotFoundError:
print('错误:找不到指定的 PDF 文件。')
except Exception as e:
print(f'发生未知错误:{str(e)}')
if __name__ == '__main__':
# 示例调用
# decrypt_pdf('encrypted.pdf')
pass
为了方便使用,可以将上述功能整合到一个脚本中。
import PyPDF2
import os
class PDFFileManager:
def __init__(self):
self.reader = None
self.writer = None
def encrypt(self, input_path, output_path, password='1234'):
"""加密 PDF"""
if not os.path.exists(input_path):
print(f'文件不存在:{input_path}')
return
with open(input_path, 'rb') as f:
reader = PyPDF2.PdfFileReader(f)
writer = PyPDF2.PdfFileWriter()
for page in range(reader.numPages):
writer.addPage(reader.getPage(page))
writer.encrypt(password)
with open(output_path, 'wb') as f:
writer.write(f)
print(f'加密完成:{output_path}')
def brute_force_decrypt(self, input_path, max_digits=4):
"""暴力破解密码"""
if not os.path.exists(input_path):
print(f'文件不存在:{input_path}')
return
with open(input_path, 'rb') as f:
reader = PyPDF2.PdfFileReader(f)
if not reader.isEncrypted:
print('文件未加密')
return
total_combinations = 10 ** max_digits
print(f'总组合数:{total_combinations}')
for i in range(total_combinations):
pwd = str(i).zfill(max_digits)
if reader.decrypt(pwd) > 0:
print(f'成功!密码:{pwd}')
# 保存解密结果
writer = PyPDF2.PdfFileWriter()
for p in range(reader.numPages):
writer.addPage(reader.getPage(p))
out_name = input_path.replace('.pdf', '_unlocked.pdf')
with open(out_name, 'wb') as f_out:
writer.write(f_out)
return
print('破解失败')
if __name__ == '__main__':
manager = PDFFileManager()
# 测试加密
# manager.encrypt('test.pdf', 'test_encrypted.pdf', '1314')
# 测试破解
# manager.brute_force_decrypt('test_encrypted.pdf')
pass
本教程演示的是 4 位纯数字密码的破解,耗时极短(通常在几秒内)。在实际应用中,这种级别的加密几乎无法提供任何安全保障。
multiprocessing 模块并行计算。rockyou.txt)优先尝试,比全排列更高效。pypdf 库以获得更好的兼容性和性能。通过 Python 的 PyPDF2 库,我们可以轻松实现 PDF 文件的加密与解密操作。虽然暴力破解弱密码非常简单,但这恰恰提醒我们在实际工作中应设置高强度的密码策略。希望本文能帮助开发者更好地理解 PDF 安全机制,并在开发过程中采取适当的安全措施。
注:本文代码仅供参考,实际生产环境请结合具体业务需求调整。

微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online
解析常见 curl 参数并生成 fetch、axios、PHP curl 或 Python requests 示例代码。 在线工具,curl 转代码在线工具,online
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online
将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online
将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online