OAEP 是一个主要应用在 RSA 中的填充算法。它的流程还算简单,我就不在此处展开了,网上有很多资料。下文默认读者至少已了解 OAEP 的大致过程。

网上的一些介绍称,OAEP 主要用来应对明文较短容易穷举的情景。由于“教科书式”RSA 的加密并未引入随机数,对于一个确定的明文,其密文也是确定的。在短密文(比如只有几个字节)的情况下,枚举成本很低,因此攻击者仅需将所有可能的明文用公钥加密即可推知密文和明文的对应关系。
但如果只是为了防止枚举和篡改,明明有更简单的方案。为避免混淆,下文将我们需要加密的消息称作是原始消息,将处理后交给 RSA 加密的数据称作明文。我之前构想的填充机制是,每次加密前生成一个随机数 r,然后计算它的散列值 h,将消息、r 和 h 拼接在一起再用 RSA 加密。引入随机数之后难以枚举或构造明文,引入散列值校验难以篡改,看起来好像还不错。这样何必要使用相对复杂的 OAEP 呢?
维基百科中关于其安全性描述的这段话很有启发性:
(笔者注:见上图,X、Y 指最终得到的两块数据,m 指的是原始消息,r 指随机数。) “全有或全无”的安全性基于以下事实:要恢复 m,必须完整地恢复 X 和 Y。从 Y 中恢复 r 需要 X,而从 X 中恢复 m 需要 r。由于加密哈希的任何更改的位都完全改变了结果,因此整个 X 和整个 Y 必须都被完全恢复。
在经过 OAEP 处理后,要得到原始消息,必须获得完整的明文,通过 X 得到 H(X),将 Y 和 H(X) 异或得到 r,进而得到 G(r),再回过来将 X 和 G(r) 异或得到原始明文加上后面拼接的若干个零。即使只缺失一小部分,原始消息就无法直接得到。当然,也可以通过若干位填充的零这个特征辅助枚举破解,但是比较困难。
所以,防止短明文枚举、构造、篡改,只是 OAEP 的附加特性罢了,在我看来它的核心是“全有或全无变换”(All-or-nothing transform):对于一个消息,要么一无所知,要么一览无余,攻击者无法退而求其次地获取其中一小部分信息。用个例子可能更容易理解:我上文构想的方案就像是将N份文档分装在N个带锁的盒子中,每个盒子有一把钥匙,攻击者只要能拿到任意一把钥匙就可以窃取一部分文档;而 OAEP 就像是将所有的N份文档装在一个盒子中,同时上N个锁,攻击者只要拿不到全部钥匙就无法窃取任何文档,一份也不行。
OAEP 借助散列算法和异或,将原始消息、随机数、冗余校验融合在一起,均匀地分散在整个可能的明文空间(不知道这个表达是否合适),使明文构成一个整体,而非分段的信息拼接。在较为极端的条件下,即使攻击者可以获取明文的部分内容,OAEP 仍可确保攻击者无法获知任何关于原始消息的有效信息。再回头看看我构想的方案,若是攻击者可以获知明文的高位,那么原始消息的部分信息就泄露了。
如果攻击者能获取完整的明文,自然就能获知原始消息,OAEP 也没有用。但在这种情况下任何填充机制都是徒劳的,这是加密算法本身该操心的问题了,不过足够密钥长度的 RSA 在短期内(公元2030年前)不会遇到这个问题。OAEP 名称中的“最优”(Optimal)二字,大概就是这个意思,它已经将自己作为填充算法的职责做得尽善尽美了,至少在目前看来是这样。