BLOG

热点跟踪 029|9 bit AES key:PDF 加密的随机数危机

永亮说AI
AI
广告 · Advertisement

发生了什么

PDF 文档加密时,用户密码并不直接加密文件内容。实际流程分两步:软件先随机生成一个 32 字节文件密钥,用 AES 加密正文;再用用户密码派生出的密钥把这个文件密钥加密保存。用户打开文档时,需要先通过密码算出派生密钥,解密出文件密钥,再用文件密钥解开正文。这个设计本身没有问题,也是很多文档加密软件的通用做法。问题在于,文件密钥的质量才是整个加密链条的根基。如果文件密钥本身很容易被猜出,那么 AES-256 算法再强也无济于事。

V12 的研究人员 Rick de Jager 在审计中发现,至少四个常见 PDF 实现中的文件密钥生成存在严重问题。问题不在于算法名不够响亮,而在于生成密钥的随机源根本没有达到密码学安全的基本要求。

先看 MuPDF 旧版本(<1.28.5)。它使用 drand48 线性同余生成器,种子是秒级 Unix 时间戳,且只从状态位 17-24 取字节。状态低 16 位固定为 0x330e,因此实际只有 9 位时间戳比特影响输出。512 秒差异内的不同时间戳可能产生完全相同的密钥流。用未优化的 Python 暴力脚本,约 11 毫秒就能遍历全部 512 种可能。攻击者一旦获得文档,很快就能枚举出正确的文件密钥。更值得警惕的是,MuPDF 的 /ID 字段同样使用同一 LCG 生成,且以明文保存,可作为额外的校验依据,进一步缩小搜索空间。

再看 Foxit PDF Reader 2026.1.3.36551。文件密钥来自「当前时间戳 + 32 个未初始化字节 + 常量」的哈希。所谓未初始化字节实际为零填充,等于没有随机性。V12 的 Rust 实现显示,在 32 线程 Ryzen 9 7950X 上每秒可测试 3.70-3.76 亿个时间戳,10 年前文件约 0.84 秒破解,从 Unix epoch 起搜索也只要约 4.85 秒。Foxit 的 /Perms 块含有已知明文,验证只需一次哈希加一次 AES 块解密,这进一步降低了攻击成本。

OpenPDF 3.0.5 与 iText 9.7.1 则是另一类问题。它们通过 IVGenerator 把本应由密码学安全随机数生成器提供的内容,替换为 ARC4 流。ARC4 种子由毫秒级时间戳和 JVM 空闲内存组成,而 /U、/O 中保存的 32 字节 salt 又以明文形式存在,可被用来反推时间戳和内存值。这意味着攻击者不需要穷举整个密钥空间,只需要根据文档中暴露的信息还原出种子即可。

V12 还指出,Foxit 中的问题代码模式可追溯到 2014 年 5 月 PDFium 的首次公开提交,而 PDFium 文件头致谢 Foxit,意味着这一模式可能源自 Foxit,已经存在了十多年。也就是说,这个隐患并非近期引入,而是长期存在于 PDF 生态中的历史包袱。更令人担忧的是,这些实现被大量下游项目和商业产品所依赖,一个底层模块的缺陷可能通过代码复用扩散到更广泛的场景中。

厂商与修复

问题已向相关厂商披露。目前公开进展如下:

  • MuPDF 已修复,受影响版本为 1.28.5 之前的版本。
  • Foxit、OpenPDF、iText 的修复状态需以各自官方公告为准。
  • V12 已发布针对 MuPDF 和 Foxit 的解密器,证明漏洞可被实际利用。

需要强调的是,已经生成的加密 PDF 文件无法被 retroactively 保护。即使软件今天修复,过去用这些版本生成的文件仍然可能处于可破解状态。这一点与常见漏洞补丁不同:补丁只能阻止新文件继续受害,旧文件的补救方式是重新用可靠工具加密或转换。

这里还涉及一个责任边界问题。PDF 加密标准本身并没有强制要求实现必须使用密码学安全随机数,也没有强制要求随机数生成器达到何种熵水平。标准只规定了算法框架,具体实现由厂商决定。结果是,不同厂商的实现质量参差不齐,用户却难以从界面或功能名称中辨别安全差异。只要文档属性里写着「AES-256」,普通用户通常就会认为足够安全。这种信息不对称,让「加密」在营销层面和实际效果之间产生了巨大落差。

另一个值得关注的点是,这类问题往往不会被传统漏洞扫描工具发现。因为代码确实调用了 AES-256,也按照标准格式存储了密钥,只是随机源本身不安全。静态分析和黑盒测试很难识别出「密钥熵不足」这类语义层面的缺陷,需要专门的安全审计才能暴露。

从另一个角度看,这次披露也暴露出代码复用带来的风险。PDF 生态中存在大量共享实现和参考代码,一旦某个基础模块对随机数的处理不够严谨,后续基于它构建的工具都可能携带相同问题。对于依赖 PDF 加密保护敏感信息的企业来说,这意味着不能简单信任知名厂商或成熟项目的名头,必须主动核实具体实现是否符合现代密码学要求。

评论区怎么说

Hacker News 的高赞评论来自 tptacek,他指出真正的问题不是「密钥只有 9 bit」,而是密钥根本就不是密码学随机。这个区分很重要:AES-256 本身没有被破解,被破解的是生成密钥的随机源。把问题描述成「9 bit AES key」是一种形象说法,但容易让读者误解为 AES 算法出了错。算法名字提供的是理论上限,实现细节决定的是实际上限。

其他讨论集中在 PDF 加密生态的历史包袱上。不少人认为,PDF 标准把加密设计得看起来复杂,却长期不强制要求实现使用密码学安全随机数,导致各类实现漏洞反复出现。PDF 加密规范诞生于文档保护需求,而非现代威胁模型,因此留下了许多灰色地带。

另一些人提醒,普通用户看到「支持 AES-256」就默认安全,但实现层面的随机数、密钥派生、盐值处理任何一环出错,都会让高强度算法名存实亡。还有评论指出,这类漏洞披露的意义在于让依赖 PDF 加密的组织重新审视自己的假设,而不是简单地把责任推给某个厂商。更有开发者表示,很多项目在选择加密方案时只关心「有没有这个功能」,而不关心实现是否经过审计,这种心态本身就是隐患的根源。

也有一部分评论关注修复的现实困难。由于 PDF 文件一旦生成便无法 retroactively 保护,企业需要重新加密大量历史文档,这对存储和流程都是额外负担。因此有人认为,这次事件的影响不会立刻消失,而是会持续数月甚至更长时间。还有人建议,未来 PDF 规范修订时应强制要求使用密码学安全随机数,否则类似问题只会不断重演。

普通用户能做三件事

  1. 不要只看「AES-256」这个标签。加密安全性取决于密钥生成、密钥派生、随机源等多个环节。如果一个工具只强调算法名称,却对实现细节含糊其辞,就要保持警惕。对于真正敏感的内容,可以考虑在 PDF 加密之外再加一层独立加密,比如使用经过审计的文件加密工具。这样即使 PDF 加密存在实现缺陷,文档内容也不会直接暴露。
  2. 检查自己是否有用受披露版本生成的敏感 PDF。如果有,建议用已修复版本的工具重新加密,或改用其他经过审计的加密方式,而不是依赖旧文件的 PDF 密码保护。需要特别注意的是,修改文档属性或重新保存不等于修复,必须重新生成文件密钥并重新加密正文。对于企业来说,这一步最好配合文档版本管理和备份策略,避免在重新加密过程中出现内容丢失或权限失控。
  3. 对企业来说,把 PDF 加密纳入安全基线审查。重点看随机数来源、密钥派生函数和盐值处理方式,而不是只看是否勾选「AES-256」。同时建立文档生命周期管理,标记哪些文件是在已知问题版本下生成的,优先对这部分文件进行重新加密或迁移。此外,安全团队可以定期关注 PDF 处理工具的安全公告,在披露出现后第一时间评估影响范围。

结语

「9 bit AES key」事件再次说明,密码学产品的安全性不是由算法名字决定的,而是由实现细节决定的。AES-256 可以提供很高的理论安全边界,但如果 32 字节密钥实际来自一个只有 9 位熵的随机源,那么它的真实强度就只有 9 bit。更麻烦的是,PDF 的加密标准并没有强制要求使用密码学安全随机数,这让问题在不同实现中反复出现。对于普通用户,最实用的动作不是去破解别人的文件,而是检查自己是否还在用存在问题的旧版本生成敏感文档,并及时迁移到更可靠的加密方式上。技术热点会过去,但文档安全不会自动修复,真正负责的做法是把这次披露当成一次整理数字资产安全状态的契机。对于依赖 PDF 加密保护核心资料的组织,这次事件是一记警钟:算法再强,也救不了随机数这一环的偷懒。只有把「实现」而不是「名称」作为评估加密产品的核心标准,才能避免类似风险再次发生。

参考来源

  • V12 安全公司博客:The case of the 9 bit AES key(2026-10-27)
  • Hacker News 讨论区,objectID 50280722(2026-10-28)
广告 · Advertisement

常见问题

PDF加密中密钥熵值不足是什么问题?

PDF加密中密钥熵值不足意味着密钥生成随机性不足,使得攻击者能够更容易地猜测或破解密钥,从而绕过加密保护。

哪些PDF实现存在文件密钥生成问题?

MuPDF旧版本、Foxit PDF Reader 2026.1.3.36551、OpenPDF 3.0.5和iText 9.7.1等PDF实现存在文件密钥生成问题。

如何修复PDF加密中的随机数生成问题?

修复PDF加密中的随机数生成问题需要厂商更新软件,使用符合密码学安全要求的随机数生成器,并确保密钥熵值达到安全标准。