← 返回密码移除工具 返回首页 English Guide
TECHNICAL EXPLAINER

网页版 PDF 密码移除工具 · 解密原理详解

本工具在浏览器本地完成 PDF 权限限制(Owner 密码)的移除,文件不上传服务器。

ⓘ
本文依据「不同 PDF 版本的加密方法对应关系」对照表,结合工具核心逻辑 unlock_core.js 的实现,逐层说明解密原理。

1PDF 加密体系概述

PDF 的安全机制由 标准安全处理器(Standard Security Handler) 实现。加密信息集中存放在文件内的 加密字典(Encryption Dictionary) 中,由 trailer 的 /Encrypt <对象号> 0 R 引用。

加密只影响两类内容:

解密需要解决两个问题:

  1. 文件密钥(File Key):由用户密码(此处为空密码)+ 加密字典内容派生;
  2. 对象密钥(Object Key):每个对象(按对象号 + 生成号)用文件密钥再派生一个独立密钥,用该密钥解密对应流/字符串,避免同一密钥直接加密全部内容。

2PDF 版本与加密方法对照表

下表为「PDF 版本 → 加密算法 → 密钥长度 → 加密字典字段」的对应关系:

PDF 版本(兼容性)加密算法密钥长度加密字典对应
PDF 1.1 / 1.2 / 1.3RC440 位/V 1 /R 2 /Length 40(无 /CF)
PDF 1.4 / 1.5RC4128 位/V 2 /R 3 /Length 128;或 /V 4 /CFM /V2 /Length 128
PDF 1.6 / 1.7AES(AES-CBC)128 位/V 4 /CFM /AESV2 /Length 128
PDF 1.7 及以后(低安全性)AES256 位/V 5 /R 5 /CFM /AESV3 /Length 256(单次 SHA-256)
PDF 1.7 及以后(高安全性)AES(AES-256 + PBKDF2)256 位/V 5 /R 6 /CFM /AESV3 /Length 256(迭代哈希)

3加密字典关键字段

字段含义示例
/Filter /Standard标准安全处理器/Filter /Standard
/V加密算法版本(1–5)/V 5
/R算法修订号(2–6)/R 6
/Length密钥长度(位,经典加密时)/Length 256
/OOwner 密码相关(32B,V<5;48B,V=5)/O <e67f...>
/UUser 密码相关(32B,V<5;48B,V=5)/U <542c...>
/OE / /UEV5:Owner/User 文件密钥的 AES 加密版本(32B)/UE <7d3a...>
/P权限位(32 位掩码,含权限标志与三位固定位)/P -3904
/CF /StdCF /CFM密码过滤器:/V2(RC4)、/AESV2(AES-128)、/AESV3(AES-256)/CFM /AESV3
/StmF / /StrF流/字符串使用的过滤器(默认 /Identity 即不加密)/StmF /StdCF
/EncryptMetadata是否加密元数据(AES-128 时影响文件密钥派生)/EncryptMetadata false

4网页版解密流程

1
读取 PDF 字节 → 定位加密字典 /Encrypt,解析 /V /R /Length /O /U /P /CFM /StmF /StrF /UE
▼
2
派生文件密钥 → V1–V4:算法 2(MD5(pw+O+P+ID0),R≥3 再迭代 50 次);V5:算法 2.B(R5 = 一次 SHA-256,R6 = AES-CBC 迭代哈希)
▼
3
校验空密码 → V1–V4:算法 6 比对 /U;V5:算法 11 校验 /U 并解密 /UE,得到 32 字节文件密钥
▼
4
逐对象派生对象密钥 → V=1 用扩展密钥(规范注 1);V≥2 用 MD5(fileKey[:n]+salt)[:n+5](AES-128 再追加 sAlT);V=5 直接用 32B 文件密钥
▼
5
解密流与字符串 → RC4 / AES-128 / AES-256-CBC;字符串含括号与 hex 两种形式
▼
6
重建输出 → 移除 /Encrypt,按解密长度平移偏移并修正 xref → 下载无权限限制的 PDF

4.1 解析加密字典

从 trailer 找到 /Encrypt <N> 0 R,按对象偏移读取加密字典文本,正则提取:

/O、/U、/UE 同时支持 hex 字符串(<...>)与 括号字符串((...))两种形式,后者需做转义还原(\(、\)、\\、八进制 \ddd 等)。

4.2 文件密钥派生

V1–V4(经典加密,算法 2)

key = MD5( password(空) + O[0:32] + P(4字节小端) + ID[0] )
对 R≥3:重复 50 次:key = MD5(key + 前3字节)
取前 n 字节(n = Length/8;n 最大 16)

注意:AES-128(V4)且 /EncryptMetadata false 时,输入末尾再追加 4 字节 FF FF FF FF。ID[0] 来自 trailer 的 /ID,参与密钥派生,因此同一文件改字节会导致密钥变化。

V5(算法 2.B)

hash = SHA-256( password + salt + udata )
count = 0
循环:
  count++
  k1 = password + hash + udata
  e  = AES-128-CBC 加密( 密钥=hash[0:16], IV=hash[16:32], 数据=k1 重复 64 次, 无padding )
  sel = (e[0]+...+e[15]) % 3        # 决定本轮用哪个哈希
  hash = SHA-256 / SHA-384 / SHA-512 ( e )
  当 count ≥ 64 且 e 末字节 ≤ count-32 时停止
key = hash[0:32]

R6 的停止条件与轮换哈希使得每次派生要做数千次 AES 块加密与哈希,这正是「高安全性」抗暴力破解的原理,也是解密耗时的主要来源之一。

4.3 密码验证(确定能否打开)

这一步同时完成了文件密钥的最终确认(实现中与 pypdf 交叉验证,R5/R6 文件密钥逐字节一致)。

4.4 对象密钥派生(算法 1 / 3)

每个对象按 对象号(3字节小端) + 生成号(2字节小端) 生成盐(salt):

加密类型对象密钥
V=1(RC4-40,无 /CF)扩展密钥 = fileKey + salt(规范注 1:V=1 时 MD5 替换为 RC4,直接用扩展密钥作 RC4 密钥);兼容生成器(pypdf 等)另按 MD5(fileKey+salt)[:n+5] 备选
V≥2 RC4MD5( fileKey[:n] + salt )[: min(n+5, 16)]
V=4 AES-128同上,salt 再追加 4 字节 sAlT
V=5 AES-256直接用 32 字节文件密钥(无 MD5、无对象盐,算法 3.1a)

RC4-40 文件的密钥选择是本工具近期修复的重点:同一派生错误会让所有流解密失败。实现采用「内容验证 + 主/备选密钥自适应」:先用规范密钥解密,若内容校验失败(解出的流不是合法 FlateDecode/图像数据)再试 MD5 备选密钥,并让字符串解密跟随流解密的统一结论。

4.5 流解密与内容验证

4.6 字符串解密

只有「经典加密(V<4)」或「加密字典显式 /StrF 非 /Identity」时字符串才加密(否则跳过,这正是某些文件书签完好的原因)。密文有两种形式:

解密结果必须保持字节长度与文本长度一致,并在替换后继续向后扫描(平移后的偏移自适应)。

4.7 输出重建

5各加密方法实现细节对照

加密方法V/R文件密钥派生对象密钥流解密密码验证
RC4-401/2算法2,5 字节扩展密钥(规范)/ MD5 备选RC4 等长 + 内容验证算法6(20 次 RC4 迭代)
RC4-1282/3 或 4/CFM V2算法2,16 字节(R3 迭代 50 次)MD5+salt[:n+5]RC4 等长 + 内容验证算法6
AES-1284/AESV2算法2 + EncryptMetadata 修正MD5+salt+sAlTAES-CBC PKCS7(Web Crypto)算法6
AES-256 低安全5/R5算法2.B:SHA-256 一次文件密钥(32B)AES-256-CBC(Web Crypto)算法11
AES-256 高安全5/R6算法2.B:迭代哈希(AES-CBC + 轮换哈希)文件密钥(32B)AES-256-CBC(Web Crypto)算法11

注:R6 迭代与 /UE 解密需要无 padding 的 AES-CBC,Web Crypto 不提供,故核心内置了纯 JS AES 块实现(SBOX/密钥扩展/CBC 链接,经 NIST 测试向量验证),这是单文件自包含的关键。

6适用范围与边界

支持

不支持 / 明确拒绝

隐私 全部逻辑运行在浏览器本地 JavaScript,文件不离开本机,无需上传。

7验证方式