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

如何提取PDF文件中的各流数据以完成解密任务?

如何从加密PDF中提取每条流数据用于自定义解密?

我正在开展一项PDF解密任务:PDF厂商采用自研方法加密每个流数据,同时提供了解密函数。已验证该解密函数可正确处理单条流数据,但PDF文件包含大量流数据,需要提取每条流数据并逐一传入解密函数处理。

加密流示例(原始PDF中)

6 0 obj
<<Length 608/Filter[/VendorPDFEncrypt/FlateDecode]>>stream
data_1
endstream
endobj

解密后对应流示例(厂商提供的解密PDF中)

2 0 obj
<<Filter[/FlateDecode]/Length 598>>stream
data_2
endstream
endobj

处理流程

encrypted pdf file -> extract each stream data -> feed it to decrypt function repeatedly-> get a readable pdf file

提取流数据的方法

方法1:使用pdfminer.six(推荐,底层精准)

pdfminer.six可以直接获取PDF中未经过任何Filter解码的原始流数据,正好匹配解密函数所需的输入:

  1. 安装依赖
pip install pdfminer.six
  1. 提取所有原始流的代码
from pdfminer.pdfparser import PDFParser, PDFDocument
from pdfminer.pdftypes import PDFStream

def extract_raw_pdf_streams(pdf_file_path):
    raw_streams = []
    with open(pdf_file_path, 'rb') as pdf_file:
        parser = PDFParser(pdf_file)
        doc = PDFDocument(parser)
        parser.set_document(doc)
        doc.initialize()

        # 遍历文档中所有对象
        for obj_item in doc.get_objects():
            obj_num, obj_gen, obj_data = obj_item
            if isinstance(obj_data, PDFStream):
                # 获取未经过任何Filter处理的原始流字节
                raw_stream_bytes = obj_data.get_raw_data()
                raw_streams.append(raw_stream_bytes)
    return raw_streams

方法2:使用PyPDF2(需调整解码设置)

PyPDF2默认会自动应用PDF标准Filter解码,需调整以获取原始加密流:

  1. 安装依赖
pip install PyPDF2
  1. 提取原始流的代码
from PyPDF2 import PdfReader

def extract_raw_streams_with_pypdf2(pdf_file_path):
    raw_streams = []
    # 初始化阅读器,关闭自动解码逻辑
    reader = PdfReader(pdf_file_path, strict=False)
    
    # 遍历所有文档对象
    for obj_id in reader._objects:
        obj = reader._objects[obj_id]
        if hasattr(obj, 'get_object'):
            obj_content = obj.get_object()
            # 判断是否为流对象
            if '/Stream' in obj_content and '/Length' in obj_content:
                # 直接获取原始流字节,跳过自动解码
                raw_stream = obj_content['/Stream']
                raw_streams.append(raw_stream)
    return raw_streams

方法3:手动解析(不推荐,仅作参考)

PDF流的结构固定为<<字典>>stream\n流数据\nendstream,可以手动遍历文件字节截取,但需处理格式细节问题:

  • 严格匹配stream和endstream关键字(PDF大小写敏感)
  • 依据字典中的/Length值确认流数据长度,避免截取错误
  • 处理流数据中的换行、空白等格式差异

手动解析示例伪代码:

def extract_streams_manual(pdf_file_path):
    streams = []
    with open(pdf_file_path, 'rb') as f:
        content = f.read().decode('latin1')
        start_marker = 'stream\n'
        end_marker = '\nendstream'
        while start_marker in content:
            start_idx = content.find(start_marker) + len(start_marker)
            end_idx = content.find(end_marker, start_idx)
            if end_idx == -1:
                break
            stream_data = content[start_idx:end_idx].encode('latin1')
            streams.append(stream_data)
            content = content[end_idx + len(end_marker):]
    return streams

后续处理建议

提取到原始流数据后,逐一传入解密函数得到解密后的流,然后:

  1. 替换原PDF中对应流的内容为解密后的数据
  2. 修改流对象字典中的/Filter,移除VendorPDFEncrypt项
  3. 更新/Length值为解密后流数据的字节长度
  4. 重新生成PDF文件

内容的提问来源于stack exchange,提问作者Tom Xue

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 18:47:09