Chapter7 对称密钥原语的实用构造
文章目录
在前面的章节中,我们已经演示了如何从诸如伪随机生成器(又称流密码)、伪随机排列(又称块密码)和哈希函数等加密原语构造安全加密方案和消息认证码。然而,我们尚未解决的一个问题是,这些加密原语最初是如何构造的,甚至它们是否存在!在下一章中,我们将从理论角度研究这个问题,并展示基于相当弱的假设的伪随机生成器和伪随机置换的构造。(事实证明,抗冲突哈希函数更难构造,似乎需要更强的假设。我们将在第9.4.2节中看到可证明的安全构造。)在本章中,我们的重点将放在这些在实践中广泛使用的原语的相对启发式但更有效的构造上。
我们将在本章中探讨的构造是启发式的,因为它们不能基于任何较弱的假设被证明是安全的。尽管如此,它们基于许多合理的设计原则,这些原则可以通过理论分析加以证明。也许更重要的是,这些构造中的许多经受住了多年的公众审查和密码分析尝试;鉴于此,假设它们是安全的是非常合理的。在某种意义上,假设(例如)因数分解是困难的,假设AES(我们将在本章稍后研究的一种分组密码)是伪随机排列,两者之间没有根本区别。然而,这些假设之间存在显著的质量差异。主要区别在于,前一种假设与较弱的要求有关:大整数难以分解的假设可以说比具有统一密钥的AES与随机排列无法区分的假设更简单、更自然。其他相关的区别在于,因子分解被研究的时间远长于区分AES与随机排列的问题,并且因子分解被数学家认为是一个难题,与任何密码应用无关。因子分解问题也被研究了更长的一段时间。
这一章的目的
本章的主要目的是(1)介绍现代密码原语构造中使用的一些设计原则,以及(2)向读者介绍现实世界中使用的某些流行方案。我们关注:
- 本章的目的不是教读者如何设计新的密码原语。相反,我们认为新原语的设计需要大量的专业知识和努力,不能轻易尝试。有兴趣在这一领域发展更多专业知识的人,请阅读本章末尾的更高级参考资料。
- 我们的目的不是呈现我们在这里讨论的各种原语的所有低级细节,我们的描述不应被依赖于实现。事实上,我们的描述有时是故意不准确的,因为我们忽略了与我们试图强调的更广泛的概念点无关的某些细节。
7.1 流密码
回想第3.6.1节,流密码由两个确定性算法(Init,Next)定义。Init算法将密钥k(有时也称为种子)和可选的初始化向量IV作为输入,并返回初始状态st。然后可以重复调用Next算法(每次调用后更新状态),以生成无边界的看似随机比特流。不采用IV的流密码应该表现得像伪随机生成器:即,当密钥k是统一的时,生成的比特序列应该与统一独立的比特序列不可区分。当流密码采用IV时,它应该像伪随机函数一样工作;也就是说,对于统一密钥k和不同的(已知的)初始化向量IV1、IV2、……IVl,使用k和每个IV生成的l比特序列应该与独立的、统一的l比特序列不可区分。我们参考第3.6.1节了解正式定义。
在本节中,我们考虑以非常不同的方式构造的三个流密码。Trivium是一种标准化的流密码,在硬件上非常有效。它基于反馈移位寄存器,这是我们在第7.1.1节和第7.1.2节中讨论的一个独立感兴趣的主题。RC4是1987年开发的一种软件优化流密码,被广泛使用了20多年。尽管已经发现了RC4中的几个弱点(并且不应该再使用它),但研究它仍然很有趣。我们最后讨论了ChaCha20,这是一种现代流密码,具有良好的软件性能,在一些互联网标准中被用作RC4的替代品。
7.1.1 线性反馈移位寄存器
我们首先讨论线性反馈移位寄存器(LFSRs)。这些在历史上被用于伪随机数生成,因为它们在硬件中实现非常有效,并且生成具有良好统计特性的输出。然而,就其本身而言,它们并没有给出密码学上强大的伪随机生成器。然而,LFSR(以及我们在下一节中讨论的它们的非线性推广)可以用作安全流密码设计的一个组件。
LFSR由n个寄存器的序列组成sn−1,…,s0以及由一组n个布尔反馈系数指定的反馈回路cn−1,…,c0。序列的大小被称为LFSR的度。每个寄存器存储一个位,并且LFSR在任何时间点的状态st由其寄存器中包含的位组成。通过将所有寄存器中的值向右移位,并将最左边寄存器的新值设置为等于由反馈系数确定的当前寄存器的某个子集的XOR,在一系列“时钟信号”中的每一个中更新LFSR的状态。也就是说,如果某个时刻t的状态是s(t)n−1,…,s(t)0,则下一个时钟节拍后的状态为s(t+1)n−1,…,s(t+1)0,满足:
图7.1显示了c0=c2=1和c1=c3=0的4级LFSR。
在每个时钟周期,LFSR输出最右边寄存器s0的值。如果LFSR的初始状态是s(0)n−1,…,s(0)0,输出流的前n位正好是s(0)0,…,s(0)n−1。下一个输出位是:
通常,如果我们用y0,y1,…表示输出位,其中yi=s(i)0,则:
作为使用图7.1中LFSR的示例,如果初始状态为(s3,s2,s1,s0)=(0,0,1,1),则前五个时间段的状态为:
(0, 0, 1, 1)
(1, 0, 0, 1)
(1, 1, 0, 0)
(1, 1, 1, 0)
(1, 1, 1, 1)并且输出(可以从上面最右边的列中读出)是位1、1、0、0、1、…的流。
度为n的LFSR可用于以自然方式定义流密码(Init,Next)。Init将n位密钥k作为输入,并将LFSR的初始状态设置为k。下一个对应于一个时钟节拍,输出单个比特并相应地更新LFSR的状态。
一个n级LFSR具有2n个可能的状态,对应于其寄存器中位的可能值。将LFSR的过渡图定义为具有对应于每个状态的顶点的有向图,并且如果在一个时钟周期中更新对应于v的状态导致对应于v’的状态,则从一个顶点v到另一个顶点v’的边。(因此,每个顶点都有一条输出边。)我们进一步用LFSR在进行相应转换时输出的位来标记图的边。例如,在图7.1中LFSR的过渡图中,顶点(1,0,0,1)有一条到顶点(1,1,0,0)的边,标记为位“1”。因此,为LFSR选择随机初始状态,然后在一系列时钟信号中更新LFSR相当于选择随机初始顶点v,然后从v开始遵循有向边的路径(并输出这些边上的相应比特)。
n级LFSR最终将重复一些先前的状态;一旦完成,它将在一组状态之间重复循环,输出的比特也将开始重复。这对应于处于过渡图的循环中。如果在重复之前LFSR循环通过所有2n−1的非零状态,则LFSR为最大长度;例如,它的过渡图包含一个通过所有2n-1个非零状态的循环。(在任何LFSR的过渡图中,全0状态都有一个自循环。如果达到全0状态,则LFSR将永远保持该状态。)如果LFSR是最大长度,那么当在任何非零状态下初始化时,它将循环通过所有2n−1个非零状态。LFSR是否为最大长度仅取决于其反馈系数。很清楚如何设置反馈系数以获得最大长度的LFSR,尽管细节超出了本书的范围。
LFSR上的密钥恢复攻击
最大长度LFSR的输出具有良好的统计特性;仅举一个例子,输出流包含大致相等数量的0和1。然而,LFSR不是安全的流密码。如果我们假设LFSR的反馈系数是已知的(正如我们应该知道的,遵循Kerckhoffs原理),那么n度LFSR的前n位输出揭示了初始状态(即密钥);一旦知道了这一点,就可以计算所有未来的输出比特。可以尝试通过使用密钥来设置反馈系数来防止这种情况;然而,即使在这种情况下,攻击者也可以在观察最多2n个输出比特后学习整个密钥。前n个输出位y0,…,yn−1显示整个初始状态。给定接下来的n个输出位yn,…,y2n−1,攻击者可以在n个未知反馈系数cn−1,…,c0中建立n个线性方程组:
可以证明,对于最大长度LFSR,上述方程是线性无关的(模2),因此唯一地确定反馈系数。因此,可以使用线性代数有效地找到系数。(如果LFSR不是最大长度,则这种攻击的变体仍然适用。)在已知反馈系数和初始状态的情况下,可以再次容易地确定LFSR的所有后续输出位。
7.1.2 添加非线性
LFSR输出位之间的线性关系使攻击变得容易。为了阻止这种攻击,我们必须引入一些非线性,即使用秘密值的AND/OR,而不仅仅是它们的XOR。这样做有几种不同的方法,我们在这里只探讨其中的一些。我们讨论的所有想法也可以以不同的方式相互结合。
非线性反馈
引入非线性的一个明显方法是使反馈回路非线性;我们将结果简单地称为反馈移位寄存器(FSR)。FSR将再次由寄存器排列组成,每个寄存器包含一个位。如前所述,通过向右移动所有寄存器中的值,在一系列时钟信号中的每一个时钟信号中更新FSR的状态;然而,现在,最左边寄存器的新值将是当前寄存器的非线性函数。换句话说,如果某个时间t的状态是s(t)n−1,…,s(t)0,则下一个时钟节拍后的状态为s(t+1)n−1,…,s(t+1)0满足:
其中g是任意非线性的。如前所述,FSR在每个时钟周期输出最右边寄存器s0的值。为了安全起见,g应该在Pr[g(sn−1,…,s0)=1]≈ 1/2,其中的概率超过均匀选择sn−1,…,s0。
非线性输出
另外一种方法是在输出序列中引入非线性。在最基本的情况下,我们可以像以前一样使用LFSR(其中最左边寄存器的新值再次计算为当前寄存器的线性函数),但其中每个时钟周期的输出是当前寄存器的非线性函数g(称为filter),而不仅仅是最右边的寄存器。这种结构有时被称为滤波器生成器。与之前一样,g应该是平衡的,这样输出流就不会有任何明显的偏差。
组合生成器
另一种可能性是使用多个LFSR,并通过以某种非线性方式组合各个LFSR的输出来生成最终输出流。这就是所谓的(非线性)组合生成器。单个LFSR不需要具有相同的度数,事实上,如果它们不具有相同的度,组合生成器的循环长度将最大化。基础LFSR的输出流的组合方式必须确保最终输出是无偏的;例如,简单地计算基础输出流的“与”将导致输出位偏向0。还必须注意确保组合生成器的最终输出不会与底层LFSR的任何输出流高度相关,因为高度相关可能导致攻击。例如,考虑通过将组合生成器的第i个输出位设置为等于yi:=(ai∧ bi)⊕ ci)来组合三个LFSR A、B和C,分别生成输出流a0、a1、…、b0、b1、…和c0、c1、……(其中∧ 表示二进制AND)。如果单个LFSR的度数为na、nb和nc,则整体状态的长度为na+nb+nc,我们可能希望区分组合生成器输出与均匀输出的最佳攻击需要时间2na+nb+nc。但请注意,如果我们将每个基础输出流的每个比特都视为统一的,那么ai∧ bi等于0的概率为3/4,因此Pr[ci=yi]=3/4。因此,给定组合生成器的长输出流y0,y1,…,攻击者可以枚举LFSR C的初始状态的所有2nc个可能值,并计算每个值的输出序列c0,c1,…。C的正确初始状态将导致与观察到的输出流大致3/4的时间一致的序列;此外,很有可能没有其他候选状态。允许攻击者在时间2nc内获得C的初始状态。这样做之后,它可以及时恢复LFSR A和B的初始状态,最多2na+nb。(请参见练习7.4了解更好的攻击。)
7.1.3 Trivium
为了说明上一节的想法,我们简要描述了流密码Trivium。该流密码被选为eSTREAM项目组合的一部分,该项目于2008年完成,其目标是开发新的流密码。Trivium被设计为具有简单的描述和紧凑的硬件实现。
如图是Trivium的示意图,包括(从上到下)三个耦合的非线性FSR A、B和C。
Trivium使用三个耦合的非线性FSR,由A、B和C表示,分别具有93、84和111度。Trivium的状态st只是288位,包括这些FSR的所有寄存器中的值。在每个时钟周期,每个FSR的输出是其最右侧寄存器和一个附加寄存器的XOR;Trivium的输出是三个FSR的输出位的XOR。FSR是耦合的:在每个时钟周期,每个FSR的最左边寄存器的新值被计算为同一FSR中的一个寄存器和来自第二FSR的寄存器子集的函数。每种情况下的反馈函数都是非线性的。
Trivium的Init算法接受80位密钥和80位IV。密钥被加载到A的最左边80个寄存器中,IV被加载到B的最左边的80个寄存器。除了C的三个最右边的寄存器设置为1之外,其余的寄存器都设置为0。然后,FSR将运行4·288个时钟周期(丢弃输出),并将生成的状态作为初始状态。迄今为止,没有比穷举搜索更好的密码分析攻击是针对Trivium的。
7.1.4 RC4
LFSR在硬件中实现时效率很高,但在软件中性能较差。因此,已经探索了流密码的替代设计。一个突出的例子是RC4。RC4以其速度和简单性而闻名,并抵御了数年的严重攻击。虽然RC4仍然偶尔使用,但最近的攻击表明RC4存在严重的密码漏洞,不再建议用于密码应用。
RC4的状态由256字节数组S组成,数组包括对0,……255元素的排列以及两个值i,j∈ {0, . . . , 255}。为了简单起见,我们假设一个16字节(128位)的密钥k,尽管该算法可以处理长度为1-256字节的密钥。我们将S的字节索引为S[0],…S[255],而密钥的字节则索引为k[0],…,k[15]。
RC4的Init算法表示为算法7.1。在初始化期间,首先将S设置为身份置换(即,对于所有i,S[i]=i),并通过根据需要多次重复将k扩展为256字节。然后,S的每个条目在某个“伪随机”位置与另一个S条目交换至少一次。索引i,j被设置为0,并且(S,i,j)作为初始状态被输出。
初始状态用于使用算法7.2中的Next算法生成输出字节序列。每次调用Next时,索引i简单地递增(模256),j以某种“伪随机”方式改变。交换条目S[i]和S[j],并输出位置S[i]+S[j]处的S值(再次计算为模256)。注意,S的每个条目至少每隔256次迭代与S的条目(可能是其自身)交换一次,以确保置换S的良好“混合”。RC4未设计为将IV作为输入;然而,在实践中,IV通常通过在初始化之前简单地将其与实际密钥k’连接而被合并。也就是说,选择所需长度的随机IV,将k设置为等于IV和k’的连接(这可以通过预加IV或附加IV来完成)然后如算法7.1中那样运行Init以生成初始状态。然后使用算法7.2产生输出比特,与之前完全相同。假设RC4在非同步模式下使用(见第3.6.2节),则IV将以明文形式发送给知道实际密钥k’的接收方,从而使发送方和接收方能够生成相同的初始状态,从而生成相同的输出流。这种结合IV的方法被用于有线等效保密(WEP)加密标准中,以保护802.11无线网络中的通信。
人们应该关注这种无原则的修改RC4以接受IV的方式。即使RC4在最初没有IV的情况下使用时是安全的,也没有理由相信它在修改为使用如上所述的IV时应该是安全的。事实上,与密钥相反,IV被泄露给攻击者(因为它是在明文中发送的);此外,使用与在非同步模式下使用RC4时相同的固定密钥k’的不同IV意味着使用相关值k来初始化RC4的状态。正如我们将在下面看到的,当RC4以这种方式使用时,这两个问题都会导致攻击。
对RC4的攻击
几年来,对RC4的各种攻击已经广为人知。因此,不应再使用RC4;相反,应该使用更现代的流密码或分组密码来代替它。我们在这里描述了一些基本的攻击,以说明所涉及的技术。
我们首先演示了对RC4的简单统计攻击,它不依赖于诚实的各方使用IV。具体来说,我们显示RC4的第二个输出字节(稍微)偏向0。设St表示在Next的t次迭代之后RC4状态的排列S,S0表示初始排列。将S0(启发式)作为{0,…,255}的均匀排列,概率1/256·(1− 1/255) ≈ 1/256它认为S0[2]=0并且X=S0[1]≠2。暂时假设情况就是这样。然后在Next的第一次迭代中,i的值增加到1,并且j被设置为等于S0[i]=S0[1]=X。然后交换条目S0[1]和S0[X],这样在迭代结束时,我们得到S1[X]=S0[1]=X。在第二次迭代中,i增加到2,j被赋值:j + S1[i] = X + S1[2] = X + S0[2] = X,因为S0[2]=0。然乎条目S1[2]=S1[X]被交换,所以S2[X] =S1[2] = S0[2] = 0并且S2[2] = S1[X] = X。最后,输出位置S2[i]+S2[j]=S2[2]+S2[X]=X处的S2值;这正好是值S2[X]=0。
当S0[2]≠0时