在密码学工程领域,算法本身的安全性与其实现质量之间往往存在难以预料的鸿沟。即使采用业界公认最强的加密标准(如 AES-256),一次看似无关紧要的代码复用失误就可能使整个安全体系崩塌。2026 年 3 月,安全研究者揭露了 Cadence PSpice 电路仿真器中一个存在长达十二年之久的加密实现漏洞:原本设计用于 AES-256 的长密钥被短密钥替换,导致有效密钥空间从 2^256 暴跌至 2^32,使得暴力破解在数秒内即可完成。这一漏洞的根源并非复杂的密码学攻击,而是一个典型的复制粘贴错误,其教训值得所有从事安全相关开发的工程师深思。
漏洞技术细节
PSpice 是 Cadence 公司推出的 SPICE 电路仿真软件,广泛用于半导体模型的仿真验证。多家第三方元件供应商以 PSpice 加密格式分发专有的 SPICE 模型文件,这种加密机制将模型锁定在特定仿真器内,阻断了工程师在 NGSpice、Xyce、PySpice 等开源或替代工具中使用这些合法获取的模型。PSpice 支持六种加密模式(0 至 5),其中模式 4 是唯一支持用户自定义密钥的模式:供应商通过 CDN_PSPICE_ENCKEYS 环境变量引用的 CSV 文件提供密钥字符串,该密钥与二进制中硬编码的基密钥进行异或运算后参与派生。
问题出在模式 4 的 AES-256 密钥派生实现中。系统维护两个基密钥字符串:短基密钥 g_desKey(4 字节,实际值为 "8gM2")和扩展基密钥 g_aesKey(27 字节,实际值为 "H41Mlwqaspj1nxasyhq8530nh1r")。当用户提供密钥时,密钥字节 0 至 3 与短基密钥异或,字节 4 至 30 与扩展基密钥异或,随后追加版本后缀(如 "1002")形成完整密钥。然而,在调用 AES-256 加密引擎时,函数 PSpiceAESEncoder_setKey 仅接收短密钥参数,而非扩展密钥。系统将这个空终止的短字符串复制到 32 字节的零初始化缓冲区中:
- 字节 0 至 3:异或后的 4 字节用户密钥(未知)
- 字节 4 至 7:版本后缀
"1002"(已知) - 字节 8:0x00 空终止符(已知)
- 字节 9 至 31:零填充(已知)
这意味着 32 字节的 AES-256 密钥中,有 28 个字节是已知的或可预测的。有效密钥空间从理论上不可破解的 2^256 缩减至仅 2^32(约 43 亿个可能值)。考虑到用户密钥存储在 CSV 文件中,每个字节几乎必然是可打印的 ASCII 字符(0x20 至 0x7E),实际搜索空间进一步压缩至约 95^4(约 8100 万个候选值),在现代硬件上可在数秒内完成穷举。
攻击向量与利用条件
该漏洞的利用并不需要复杂的密码学知识。加密文件以 $CDNENCSTART 标记作为元数据头部的起始位置,而该元数据块的头 16 字节密文对应的明文始终以固定前缀 "0001.0000 "(10 个 ASCII 字节)开头。这一已知明文 crib 提供了直接的验证机制:攻击者只需提取密文的头 16 字节,遍历 2^32 个候选密钥值,解密后检查前 10 字节是否匹配该前缀,即可确认密钥正确性。
更进一步的攻击可以完全恢复用户密钥字符串。一旦短密钥(4 字节)通过暴力穷举恢复,解密元数据头部后可获得嵌入的扩展密钥信息。通过将恢复的扩展密钥与已知的基密钥进行异或运算,攻击者能够重建 CSV 文件中的完整用户密钥字符串,从而解密所有使用该密钥加密的文件。这种二次恢复能力意味着供应商一旦泄露或被穷举出密钥,多年积累的加密模型资产将面临系统性风险。
根因分析
从代码逆向工程的视角审视,这一漏洞的根因清晰而令人警醒。研究者根据二进制中的符号还原了变量名:g_desKey 和 g_aesKey—— 这两个名称本身就暗示了设计意图。短密钥长度为 8 字节(4 异或字节加 4 字节版本后缀),恰好匹配 DES 密钥的典型长度;扩展密钥长度为 31 字节加空终止符以填满 32 字节,正好满足 AES-256 对密钥材料的要求。看起来,开发团队在实现 AES-256 支持时,将原有的 DES 加密代码路径复制过来,却忘记将传递给加密引擎的参数从短密钥更换为扩展密钥。
这一错误在 AES-256 支持首次引入 PSpice 16.6 版本时(2014 年 4 月)就已存在,此后的十二年间从未被发现或修复。讽刺的是,修复此漏洞的难度并不在于密码学理论的突破,而仅需将正确的扩展密钥变量传递给加密引擎。然而,鉴于已有大量加密模型文件基于此错误实现生成,任何修复都将导致这些文件无法解密,形成了对向后兼容性的沉重依赖。
工程启示与防范建议
这起事件为密码学工程实践提供了若干关键教训。首先,密钥派生与密钥使用之间的职责边界必须严格划分:在本例中,密钥派生逻辑正确生成了两种不同长度的密钥,但密钥使用环节错误地选择了较短的那个。代码审查应重点关注这类跨函数、跨模块的调用链,确保传递给加密原语的参数与预期用途严格匹配。
其次,测试用例应覆盖密钥空间的完整性验证。对于 AES-256 实现,自动化测试应验证密钥是否真正利用了全部 256 位熵源,而非仅检查加密解密操作是否成功执行。可以通过 entropy estimation 工具或简单的密钥变异测试来检测是否存在已知字节位置。
第三,安全关键代码的复制粘贴需要额外审慎。代码复用是软件工程的常见实践,但在密码学实现中,复制一个函数可能同时复制了设计假设和约束条件。DES 接受 8 字节密钥,AES-256 需要 32 字节 —— 这种差异不应被忽视。
对于使用 PSpice 加密模型的工程师而言,短期内应意识到模式 4 加密并不能提供真正的 AES-256 强度保护。如果模型涉及高度敏感的知识产权,应考虑在模型交付前额外应用独立的加密层,或与供应商协商使用其他保护机制。长期来看,该漏洞的修复需要 Cadence 在保持向后兼容性的前提下重新设计密钥派生架构。
资料来源:本文技术细节主要参考 jtsylve.blog 上发布的《A Copy-Paste Bug That Broke PSpice® AES-256 Encryption》一文,该文详细披露了漏洞的逆向工程分析、攻击方法及 SpiceCrypt 工具的实现原理。