了解如何使用 PyPDF4 库为 PDF 文件添加和删除密码,以及如何使用 pyAesCrypt 在 Python 中加密和解密 PDF 文件。
如何在Python中加密和解密PDF文件?你想要加密 PDF 文件的目的有很多,其中之一是阻止某人将你的 PDF 复制到他们的计算机并使其只能使用解密密钥使用。使用加密的 PDF 文件,你可以防止不受欢迎的人查看 PDF 文件中的个人或凭据信息。
Python如何加密和解密PDF文件?在本教程中,你将学习如何通过应用两个保护级别来加密 PDF 文件:
- 级别 1:通过添加文档打开密码来限制对 PDF 文件的访问。文档打开密码(也称为用户密码)需要用户输入密码才能打开 PDF。
- 级别 2:使用pyAesCrypt 库和使用AES256-CBC加密算法加密文件。
Python加密和解密PDF文件示例:本教程的目的是通过基于 Python 的模块开发一个轻量级的基于命令行的实用程序,而不依赖于 Python 生态系统之外的外部实用程序(例如qpdf),以保护 Python 中的 PDF 文件。
在开始之前,让我们安装所需的库:
$ pip install PyPDF4==1.27.0 pyAesCrypt==6.0.0
让我们在 Python 文件中导入必要的库:
# Import Libraries
from PyPDF4 import PdfFileReader, PdfFileWriter, utils
import os
import argparse
import getpass
from io import BytesIO
import pyAesCrypt
首先,让我们定义一个函数来检查 PDF 文件是否被加密:
# Size of chunck
BUFFER_SIZE = 64*1024
def is_encrypted(input_file: str) -> bool:
"""Checks if the inputted file is encrypted using PyPDF4 library"""
with open(input_file, 'rb') as pdf_file:
pdf_reader = PdfFileReader(pdf_file, strict=False)
return pdf_reader.isEncrypted
其次,让我们制作核心功能,即加密PDF文件:
def encrypt_pdf(input_file: str, password: str):
"""
Encrypts a file using PyPDF4 library.
Precondition: File is not encrypted.
"""
pdf_writer = PdfFileWriter()
pdf_reader = PdfFileReader(open(input_file, 'rb'), strict=False)
if pdf_reader.isEncrypted:
print(f"PDF File {input_file} already encrypted")
return False, None, None
try:
# To encrypt all the pages of the input file, you need to loop over all of them
# and to add them to the writer.
for page_number in range(pdf_reader.numPages):
pdf_writer.addPage(pdf_reader.getPage(page_number))
except utils.PdfReadError as e:
print(f"Error reading PDF File {input_file} = {e}")
return False, None, None
# The default is 128 bit encryption (if false then 40 bit encryption).
pdf_writer.encrypt(user_pwd=password, owner_pwd=None, use_128bit=True)
return True, pdf_reader, pdf_writer
如何在Python中加密和解密PDF文件?该encrypt_pdf()
函数执行以下操作:
- 它验证输入的 PDF 文件未使用PyPDF4库加密。
- 它遍历它的页面并将它们添加到一个
pdf_writer
对象中。 pdf_writer
使用给定的密码加密对象。
现在我们有了负责加密的函数,让我们做相反的事情,那就是解密:
def decrypt_pdf(input_file: str, password: str):
"""
Decrypts a file using PyPDF4 library.
Precondition: A file is already encrypted
"""
pdf_reader = PdfFileReader(open(input_file, 'rb'), strict=False)
if not pdf_reader.isEncrypted:
print(f"PDF File {input_file} not encrypted")
return False, None, None
pdf_reader.decrypt(password=password)
pdf_writer = PdfFileWriter()
try:
for page_number in range(pdf_reader.numPages):
pdf_writer.addPage(pdf_reader.getPage(page_number))
except utils.PdfReadError as e:
print(f"Error reading PDF File {input_file} = {e}")
return False, None, None
return True, pdf_reader, pdf_writer
该函数执行以下操作:
- 它验证输入的 PDF 文件是否使用PyPDF4库加密。
- 它
pdf_reader
使用密码(必须是正确的)解密对象。 - 它遍历它的页面并将它们添加到一个
pdf_writer
对象中。
让我们进入第 2 级,加密实际文件:
def cipher_stream(inp_buffer: BytesIO, password: str):
"""Ciphers an input memory buffer and returns a ciphered output memory buffer"""
# Initialize output ciphered binary stream
out_buffer = BytesIO()
inp_buffer.seek(0)
# Encrypt Stream
pyAesCrypt.encryptStream(inp_buffer, out_buffer, password, BUFFER_SIZE)
out_buffer.seek(0)
return out_buffer
通过使用pyAesCrypt库,上述函数加密输入内存缓冲区并返回加密的内存缓冲区作为输出。
现在让我们制作文件解密功能:
def decipher_file(input_file: str, output_file: str, password: str):
"""
Deciphers an input file and returns a deciphered output file
"""
inpFileSize = os.stat(input_file).st_size
out_buffer = BytesIO()
with open(input_file, mode='rb') as inp_buffer:
try:
# Decrypt Stream
pyAesCrypt.decryptStream(
inp_buffer, out_buffer, password, BUFFER_SIZE, inpFileSize)
except Exception as e:
print("Exception", str(e))
return False
inp_buffer.close()
if out_buffer:
with open(output_file, mode='wb') as f:
f.write(out_buffer.getbuffer())
f.close()
return True
以上Python加密和解密PDF文件示例中的decipher_file()
,我们使用pyAesCrypt模块中的decryptStream()
方法,它接受输入和输出缓冲区、密码、缓冲区大小和文件大小作为参数,并将解密后的流写入输出缓冲区。
Python如何加密和解密PDF文件?为了更方便地使用文件的加解密,建议大家阅读本教程,该教程使用了对Python开发者更友好的加密模块。
现在让我们将我们的功能合并为一个:
def encrypt_decrypt_file(**kwargs):
"""Encrypts or decrypts a file"""
input_file = kwargs.get('input_file')
password = kwargs.get('password')
output_file = kwargs.get('output_file')
action = kwargs.get('action')
# Protection Level
# Level 1 --> Encryption / Decryption using PyPDF4
# Level 2 --> Encryption and Ciphering / Deciphering and Decryption
level = kwargs.get('level')
if not output_file:
output_file = input_file
if action == "encrypt":
result, pdf_reader, pdf_writer = encrypt_pdf(
input_file=input_file, password=password)
# Encryption completed successfully
if result:
output_buffer = BytesIO()
pdf_writer.write(output_buffer)
pdf_reader.stream.close()
if level == 2:
output_buffer = cipher_stream(output_buffer, password=password)
with open(output_file, mode='wb') as f:
f.write(output_buffer.getbuffer())
f.close()
elif action == "decrypt":
if level == 2:
decipher_file(input_file=input_file,
output_file=output_file, password=password)
result, pdf_reader, pdf_writer = decrypt_pdf(
input_file=input_file, password=password)
# Decryption completed successfully
if result:
output_buffer = BytesIO()
pdf_writer.write(output_buffer)
pdf_reader.stream.close()
with open(output_file, mode='wb') as f:
f.write(output_buffer.getbuffer())
f.close()
如何在Python中加密和解密PDF文件?上面的函数接受 5 个关键字参数:
input_file
:输入的PDF文件。output_file
:输出PDF文件。password
:要加密的密码字符串。action
:接受“加密”或“解密”操作作为字符串。level
:你要使用哪种级别的加密。将其设置为1
仅在打开 PDF 文件时2
添加密码,添加文件加密作为另一层安全性。
现在,让我们创建一个新类,该类继承自argparse.Action
以安全输入密码:
class Password(argparse.Action):
"""
Hides the password entry
"""
def __call__(self, parser, namespace, values, option_string):
if values is None:
values = getpass.getpass()
setattr(namespace, self.dest, values)
它覆盖 __call__()
方法并将对象的dest
变量设置为namespace
用户使用getpass模块输入的密码。
接下来,让我们定义解析命令行参数的函数:
def is_valid_path(path):
"""Validates the path inputted and checks whether it is a file path or a folder path"""
if not path:
raise ValueError(f"Invalid Path")
if os.path.isfile(path):
return path
elif os.path.isdir(path):
return path
else:
raise ValueError(f"Invalid Path {path}")
def parse_args():
"""Get user command line parameters"""
parser = argparse.ArgumentParser(description="These options are available")
parser.add_argument("file", help="Input PDF file you want to encrypt", type=is_valid_path)
# parser.add_argument('-i', '--input_path', dest='input_path', type=is_valid_path,
# required=True, help="Enter the path of the file or the folder to process")
parser.add_argument('-a', '--action', dest='action', choices=[
'encrypt', 'decrypt'], type=str, default='encrypt', help="Choose whether to encrypt or to decrypt")
parser.add_argument('-l', '--level', dest='level', choices=[
1, 2], type=int, default=1, help="Choose which protection level to apply")
parser.add_argument('-p', '--password', dest='password', action=Password,
nargs='?', type=str, required=True, help="Enter a valid password")
parser.add_argument('-o', '--output_file', dest='output_file',
type=str, help="Enter a valid output file")
args = vars(parser.parse_args())
# To Display Command Arguments Except Password
print("## Command Arguments #################################################")
print("\n".join("{}:{}".format(i, j)
for i, j in args.items() if i != 'password'))
print("######################################################################")
return args
最后,编写主要Python加密和解密PDF文件示例代码:
if __name__ == '__main__':
# Parsing command line arguments entered by user
args = parse_args()
# Encrypting or Decrypting File
encrypt_decrypt_file(
input_file=args['file'], password=args['password'],
action=args['action'], level=args['level'], output_file=args['output_file']
)
好的,让我们测试我们的程序。首先,让我们通过--help
看看参数:
$ python encrypt_pdf.py --help
输出:
usage: encrypt_pdf.py [-h] [-a {encrypt,decrypt}] [-l {1,2}] -p [PASSWORD] [-o OUTPUT_FILE] file
These options are available
positional arguments:
file Input PDF file you want to encrypt
optional arguments:
-h, --help show this help message and exit
-a {encrypt,decrypt}, --action {encrypt,decrypt}
Choose whether to encrypt or to decrypt
-l {1,2}, --level {1,2}
Choose which protection level to apply
-p [PASSWORD], --password [PASSWORD]
Enter a valid password
-o OUTPUT_FILE, --output_file OUTPUT_FILE
Enter a valid output file
太棒了,让我们加密一个示例 PDF 文件(在此处获取):
$ python encrypt_pdf.py bert-paper.pdf -a encrypt -l 1 -p -o bert-paper-encrypted1.pdf
这将提示输入两次密码:
Password:
Password:
## Command Arguments #################################################
file:bert-paper.pdf
action:encrypt
level:1
output_file:bert-paper-encrypted1.pdf
######################################################################
Python如何加密和解密PDF文件?使用密码保护的新 PDF 文件将出现在当前工作目录中,如果你尝试使用任何 PDF 阅读器程序打开它,你将收到密码提示,如下图所示:
显然,如果你输入错误的密码,你将无法访问 PDF 文件。
如何在Python中加密和解密PDF文件?接下来,让我们现在解密它:
$ python encrypt_pdf.py bert-paper-encrypted1.pdf -a decrypt -p -l 1 -o bert-paper-decrypted1.pdf
输出:
Password:
## Command Arguments #################################################
file:bert-paper-encrypted1.pdf
action:decrypt
level:1
output_file:bert-paper-decrypted1.pdf
######################################################################
太棒了,你会注意到bert-paper-decrypted1.pdf出现在你的目录中,它与原始(未加密)等效。
结论
综合以上的Python加密和解密PDF文件示例,请注意,如果你选择级别 2,则整个文件将被加密,因此你需要对其进行两次解密,首先使用级别 2,然后使用级别 1。
你需要注意通过添加文档打开密码锁定 PDF 文件可以使用多种方法绕过,其中之一是破解 PDF 密码,请查看本教程以了解如何操作。