摘要

  • RFC 1991 的默认组合顺序是先签名,再把签名包与字面数据包一起压缩,随后用一次性会话密钥加密,最后为每个收件人加上公钥加密的会话密钥包;变换顺序决定签名究竟覆盖哪些字节。
  • ASCII Armor 解决二进制对象穿越文本邮件通道的问题,CTB 解决包类型与长度边界的问题。Armor CRC、合法类型和长度一致都是格式收据,不是作者身份、可信时间或授权证明。
  • 普通文档签名只覆盖字面数据及规定的签名分类与时间字段;字面包的文件名、模式和时间并不因此成为已签事实。

先问“哪一层成功”

1996 年的一名收件人面对的,表面上只是一封“PGP 邮件”。但 RFC 1991 记录的不是一个不可分割的安全容器,而是一组有先后关系的对象。最外层可能是可打印的 ASCII Armor。还原后,是一个或多个可以串接、也可以嵌套的 packet。收件人的公钥加密包携带会话密钥入口,常规密文包封住内部内容,压缩包再包住签名包和字面数据包。

所以,“PGP 成功”不是一个足够精确的审计结论。Armor 成功说明文本可还原;CTB 成功说明解析器找到了一个宣称的类型和边界;解密成功说明某条密钥路径产生了可继续处理的字节;验签成功说明某把公钥与特定字节之间的密码学关系成立。四者相关,却互不替代。

这种分层并非后来人为加上的谨慎。它写在格式的排列方式里。RFC 1991 的贡献,是把复杂过程压成软件可以逐层逆转的最小公共语法。它没有把自然人身份、业务授权或收件人的行为也塞进同一个语法。

顺序决定签名的辖区

当签名与保密同时使用时,发送端先对消息签名,把签名包置于消息前;默认再压缩签名包与字面数据包;然后用一次性会话密钥加密压缩结果;最后为每个收件人用其公钥加密会话密钥,并把相应的公钥加密包放在密文前面。

这一顺序解释了为什么外层不能替内层作证。ASCII Armor 在最后包住二进制结果,所以普通文档签名并不覆盖 Armor header。加密发生在签名之后,所以解出密文只是让验签成为可能,并不自动得出签名通过。压缩位于二者之间,所以解压器重建出的 packet sequence 必须另行记录;只保存最终显示文本,会丢掉判断覆盖对象所需的中间事实。

字面数据包把边界画得更细。它含有模式、建议文件名、时间字段和字面数据。RFC 1991 明确规定,形成文档签名时只把字面数据字段送入摘要函数。文件名看起来像来源信息,时间看起来像文件事实,模式可能影响本地写入,但它们不是这份文档签名所保护的内容。

分离签名与嵌套签名也说明同一个问题。多个人可以各自对同一份文件做 detached signature;若逐层嵌套,后一位签名者签的就不只是文档,还包括前一个签名。记录“两个签名都有效”仍然不够,必须说明每个签名的 primary input 是什么。

CTB 给解析器地图,不给对象身份证

packet structure field 的首字节是 CTB。若干位说明这是签名包、压缩包、常规密文包、公钥加密包或字面数据包;另外两位说明长度字段占一、二、四个字节,或不提供显式长度。压缩数据曾使用无长度形式,含义是一直延伸到 enclosing structure 的末尾,且不应出现在最外层文件位置。

这是很重要的工程约束。接收端无需猜测每个对象从哪里开始、在哪里结束,嵌套结构也能够被稳定拆开。但 CTB 只能证明首字节符合一种语法解释,长度只能证明解析器按照声明抵达边界。它们不能证明 body 可信、发送者是谁、算法实现安全,也不能证明 enclosing structure 本身完整。

无长度压缩包尤其说明“边界”依赖上下文。只有外层边界已经可靠,直到外层结束才是确定的含义。局部能解析,不等于整体语境正确。

Armor 的职责是穿越邮件通道

早期邮件系统未必能无损传输任意 8-bit 字节。RFC 1991 因此用 radix-64 把每三个二进制字节映射成四个可打印字符,并避开可能被邮件系统改写的字符。Armor 由头行、可选头字段、空行、编码数据、24-bit CRC 和尾行组成。

可见边框和校验值很容易营造“已经封签”的印象,RFC 却主动收窄了它的权限。Armor header 属于 armor,不属于 message;它可能在传输中改变,因此不得承载重要信息。遇到未知但格式正确的 header,程序应向用户报告后继续处理。

CRC 通过,只说明转换前的二进制数据与收到的 armored body 在该检错机制下相符。它擅长发现传输差错,却没有密钥,也没有身份语义。任何人都可以替换整块内容并重算 CRC。Armor 可以证明运输包装的局部一致性,不能证明谁包装、为何包装、内部签名是否有效,或收件人是否接受。

解开密文仍不是找到行为人

常规密文的明文前缀含随机字节和重复的 key-check bits。解密后相应字节吻合,实现便假定会话密钥正确。公钥加密的 DEK 也带有局部 checksum。这些检查能迅速排除错误密钥路径,却不等同于消息认证。

一次成功解密说明某个私钥与当时状态可以打开该 ciphertext。它没有说明谁调用了私钥、调用是否合法、端点是否被攻破、所有内容是否完整处理,或者预定收件人是否看过明文。

公钥加密包内的 64-bit key ID 同样只是候选选择器。RFC 1991 明说两把密钥可能偶然或恶意共享一个 ID。短 ID 不是密钥唯一性证明,更不是自然人身份证。审计记录必须另外保存实际候选、密钥材料或更强标识、生命周期状态及使用依据。

签名有效以后,身份与时间仍待证明

签名包把文档字节与签名分类、签名时间等规定字段纳入摘要,再由公钥验证。分类本身也有差异:binary document、canonical text、不同强度的 key/user ID certification、revoke 与 timestamping 不是同一种陈述,部分类型在 PGP 2.6.2 甚至没有实现或不会输出。

普通签名时间看似精确,RFC 却说它通常接近签名包创建时刻,但并无强制要求,用户可以自行选择日期。若需要可信时间,要另由受信时间服务对签名包再次签名。验签成功不能自动证明新鲜性、未重放或法律意义上的签署时间。

User ID packet 只是与密钥关联的可打印 ASCII 字符串。即使 certification signature 有效,依赖方仍要决定信任哪位认证者、采用哪种核验强度、在什么时点判断密钥有效。现实中的自然人身份、组织职位和行动权限不由字符串自行产生。

格式记录事实,不替系统作决定

RFC Editor 信息页把 RFC 1991 列为 Informational,并注明后来被 RFC 4880 取代;IETF 文档页、规范的 HTML 与 TXT 保存了这份 1996 年记录。文档地位证明出版谱系,不证明普遍部署、实现一致或现代安全适用性。

所链接的 IETF 名录条目只提供机构导航;它不构成 IETF 对本文解释的认可证据。

用恒路关于运行代码优先、最小初始规范与本地未来决定以及现实层与符号层的分层方法来看,RFC 1991 很像一份克制的公共协议:共同层规定足够让各方本地解析和验证的格式,后续身份、信任、授权与执行仍归负责这些结果的系统。这里引用这些文章是公开的编辑方法,而不是 PGP 历史证据。

真正可靠的结论不是“PGP 已验证”,而是逐层留下收据:哪些字符还原了哪些字节,哪些 CTB 划出了哪些包,哪把密钥打开了哪个会话密钥,解密和解压产生了什么,哪份签名覆盖了哪些字节,谁在何时控制密钥,哪项规则授予权限,最后哪个系统或人做了什么。