如何在Python中加密和解密PDF文件(代码实现示例)

了解如何使用 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*1024def 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文件(代码实现示例)】如何在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] fileThese options are availablepositional arguments: fileInput PDF file you want to encryptoptional arguments: -h, --helpshow 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 阅读器程序打开它,你将收到密码提示,如下图所示:
如何在Python中加密和解密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 密码,请查看本教程以了解如何操作。

    推荐阅读