如果把 AES、DES 等各种加密算法排列组合,然后对一明文进行逐一加密,这样的组合加密算法强度大吗?

题主的这个问题问得很不错,很适合展开写一篇关于密码学的科普,给没有相关背景的程序员普及一些密码学常识。

为了那些没有耐心读完全文的读者,我先把结论提到最开头:这样的组合加密存在安全缺陷,两个算法的组合,其强度仅仅相当于强度最高的那个算法;三个及以上的算法组合才有可能胜过强度最高的那个算法,但是仍弱于密码本身应有的强度。以上结论可给出严谨的数学证明,而且高中/本科水平的知识应该就足以理解。

另外,我在下面回答里看到有人提到了香农的乘积密码(Product Cipher),但是乘积密码和本题描述的情况其实并不完全相同,这一点我会放在文末讲。


密码学的安全模型

在正式开始之前,我们要先讲清楚一个问题:现代密码学到底是如何判断一个加密算法安全与否的?如果对这一点没有一个严谨的定义的话,接下来的论证是没法展开的。

现代密码学中考察一个加密算法的安全性时,一定会假设攻击者知道算法的所有细节,只是不知道密钥而已。这个假设被称作柯克霍夫原则(Kerckhoffs’s Principle),是我们从历史上无数失败的保密系统中学到的经验教训——永远不要依赖保密算法来保证系统的安全性。

在柯克霍夫原则的基础上,密码学家一般会进一步假设攻击者能够发动选择明文攻击(Chosen-Plaintext Attack)或者稍弱一点的已知明文攻击(Known-Plaintext Attack)

  • 选择明文攻击,指攻击者能够自由选择若干明文,然后拿到对应的密文。
  • 已知明文攻击,则是说攻击者没有选择权,但是能够窃取到若干组明文密文。

这两种攻击乍一看有些苛刻,但是在大范围应用的过程中往往无法避免。因此对加密算法进行理论分析的时候,必须采用这样的威胁模型来进行考量。

加密算法的强度

在文章的最开头,我提到了一个概念:加密算法的强度(bits of security),那么这个强度是怎么定义的呢?

假定我们有一个加密算法,它的密钥长度有256位,那么进行穷举破解就需要进行 2^{256} 次计算。我们把这个计算量,视作这个算法理论上讲应有的强度,即 256 bits of security。

如果有一天突然有人发现这个算法存在数学上的漏洞,想要找到密钥只需要进行 2^{128} 次计算就够了,那么我们就说这个算法的强度降低到了128位,即 128 bits of security。

比较著名的例子是当年美国制定的3DES(Triple DES)算法,从168位的加密强度一路掉到了现在NIST钦定的80位,基本就相当于一个废物加密算法了。


组合加密算法安全性的数学论证

首先我们来考虑只有两个加密算法组合的情况。在这段论证中,我将会采用实现难度更低的已知明文攻击,这样能够更好地说明组合加密算法的脆弱程度。

假定存在两个加密算法 E_1, E_2 ,它们俩的密钥长度分别为 \ell_1, \ell_2 ,且加密强度与密钥长度持平。

假定存在密钥 k_1, k_2 ,对于任意明文 m ,我们先使用 E_1, k_1 加密,再使用 E_2,k_2 加密,得到密文 c = E_{2,k_2}(E_{1,k_1}(m))

那么在这种情况下,如果用 E_2,k_2 来解密c ,应该会得到跟 E_1, k_1 加密 m 一样的结果,也就是说存在一个中间值 i = E_{2,k_2}^{-1}(c) = E_{1,k_1}(m)

不失一般性地,我们假定 \ell_1 \geq \ell_2 ,也就是说 E_1 的密钥更长、强度更强。

假定攻击者已经拿到了一条长度为 L 的明文 m' ,以及对应的密文 c'

密钥 k_12^{\ell_1} 种可能的取值,那么 m' 也就有 2^{\ell_1} 种相应的中间值 i=E_{1,k_1}(m') 。我们先建立一个表,将每一对可能的 k_1i 都保存下来,这个步骤需要花费 2^{\ell_1} 次运算。

接下来我们开始穷举 k_2k_2 一共有 2^{\ell_2} 种可能的取值,每种取值对应一个中间值 i = E_{2,k_2}^{-1}(c') 。我们每算出一个中间值来,就在之前建立的表里面查找这个中间值。如果当初建表使用的是哈希表的话(比如DHT),那么这个查表操作只需要常数项的运算时间就能完成。

好,那么我们回过头来解释一个点——为什么之前要提一句明文长度为 L 呢?因为如果长度不够长的话,我们查表可能会查到假密钥(false key),也就是说这个密钥虽然跟真密钥不同,但是算出来的 (m', c') 恰好与真密钥一致。

对于我们的组合算法而言,一共有 2^{\ell_1+\ell_2} 种可能的密钥,算出一个假密钥的概率是 1/2^{L},也就是说我们的 L 必须显著大于 \ell_1+\ell_2 才能基本避免出现假密钥。万幸,这个条件很好达成,你只要收集1KB的数据基本就够用了。

最后总结一下,在整个过程中,建表花费了 2^{\ell_1} 次运算,查表进行了 2^{\ell_2} 次,那么总的运行时间就是 2^{\ell_1}+ 2^{\ell_2} \approx O(2^{\ell_1}) ,这个组合加密的强度仅仅和 E_1 持平而已。

以上证明可以通过归纳法推广到三个及以上的算法组合,但这里空间太小,我懒得写了。


最后聊聊乘积密码

这道问题下面有人提到了乘积密码,为什么我说乘积密码和这个不是一个情况呢?因为乘积密码从一开始就是作为一个整体来设计的,在乘积密码运算的过程中,不会暴露出一个中间值供你攻击。

以DES加密为例,密钥一共有56位。你说我能不能找个地方截断一下,比如我知道前24位的话我能正着算一个中间值,知道后32位我能倒着算一个中间值,然后重演上文所述的攻击,可以吗?不可以。DES的每步运算都是和每位密钥息息相关的,你裁出一节密钥来什么也算不出来。

但是本题所述的组合密码就不同了,不管你结合的方式再巧妙,不同的加密算法本来就是不同的整体。一个AES-128算法不管你做什么操作,它的运算就是由128位密钥决定的。你说我加密之前对这128位数据做了一串神仙操作,这128位的值是基于前面的多少多少位变化的,那都无所谓。进到AES-128算法里做加密的,还是128位二进制数据,我知道实际进去的128位数据是多少就完事了,其他数据不可能再对加密过程产生任何影响,任何的小聪明从数学角度讲都没有意义。

来源:知乎 www.zhihu.com

作者:Gh0u1L5

【知乎日报】千万用户的选择,做朋友圈里的新鲜事分享大牛。
点击下载

此问题还有 8 个回答,查看全部。